static int entersafe_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu, u8 * key, size_t keylen, int cipher,int mac) { u8 *cipher_data=0,*mac_data=0; size_t cipher_data_size,mac_data_size; int blocks; int r=SC_SUCCESS; SC_FUNC_CALLED(card->ctx, 1); assert(card); assert(apdu); if((cipher||mac) && (!key||(keylen!=8 && keylen!=16))) SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS); if (card->ctx->debug >= 6) { u8 *sbuf=NULL; size_t ssize=0; r = sc_apdu_get_octets(card->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW); if (r == SC_SUCCESS) sc_apdu_log(card->ctx, sbuf, ssize, 1); free(sbuf); } if(cipher) { blocks=(apdu->lc+2)/8+1; cipher_data_size=blocks*8; cipher_data=malloc(cipher_data_size); if(!cipher) { r = SC_ERROR_OUT_OF_MEMORY; goto out; } if((r = entersafe_cipher_apdu(card,apdu,key,keylen,cipher_data,cipher_data_size))<0) goto out; } if(mac) { mac_data_size=apdu->lc+4; mac_data=malloc(mac_data_size); r = entersafe_mac_apdu(card,apdu,key,keylen,mac_data,mac_data_size); if(r<0) goto out; } r = sc_transmit_apdu(card,apdu); out: if(cipher_data) free(cipher_data); if(mac_data) free(mac_data); SC_FUNC_RETURN(card->ctx, 3, r); }
static int pcsc_transmit(sc_reader_t *reader, sc_slot_info_t *slot, sc_apdu_t *apdu) { size_t ssize, rsize, rbuflen = 0; u8 *sbuf = NULL, *rbuf = NULL; int r; /* we always use a at least 258 byte size big return buffer * to mimic the behaviour of the old implementation (some readers * seems to require a larger than necessary return buffer). * The buffer for the returned data needs to be at least 2 bytes * larger than the expected data length to store SW1 and SW2. */ rsize = rbuflen = apdu->resplen <= 256 ? 258 : apdu->resplen + 2; rbuf = malloc(rbuflen); if (rbuf == NULL) { r = SC_ERROR_MEMORY_FAILURE; goto out; } /* encode and log the APDU */ r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, slot->active_protocol); if (r != SC_SUCCESS) goto out; if (reader->ctx->debug >= 6) sc_apdu_log(reader->ctx, sbuf, ssize, 1); r = pcsc_internal_transmit(reader, slot, sbuf, ssize, rbuf, &rsize, apdu->control); if (r < 0) { /* unable to transmit ... most likely a reader problem */ sc_error(reader->ctx, "unable to transmit"); goto out; } if (reader->ctx->debug >= 6) sc_apdu_log(reader->ctx, rbuf, rsize, 0); /* set response */ r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize); out: if (sbuf != NULL) { sc_mem_clear(sbuf, ssize); free(sbuf); } if (rbuf != NULL) { sc_mem_clear(rbuf, rbuflen); free(rbuf); } return r; }
static int openct_reader_transmit(sc_reader_t *reader, sc_slot_info_t *slot, sc_apdu_t *apdu) { size_t ssize, rsize, rbuflen = 0; u8 *sbuf = NULL, *rbuf = NULL; int r; rsize = rbuflen = apdu->resplen + 2; rbuf = malloc(rbuflen); if (rbuf == NULL) { r = SC_ERROR_MEMORY_FAILURE; goto out; } /* encode and log the APDU */ r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW); if (r != SC_SUCCESS) goto out; if (reader->ctx->debug >= 6) sc_apdu_log(reader->ctx, sbuf, ssize, 1); r = openct_reader_internal_transmit(reader, slot, sbuf, ssize, rbuf, &rsize, apdu->control); if (r < 0) { /* unable to transmit ... most likely a reader problem */ sc_error(reader->ctx, "unable to transmit"); goto out; } if (reader->ctx->debug >= 6) sc_apdu_log(reader->ctx, rbuf, rsize, 0); /* set response */ r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize); out: if (sbuf != NULL) { sc_mem_clear(sbuf, ssize); free(sbuf); } if (rbuf != NULL) { sc_mem_clear(rbuf, rbuflen); free(rbuf); } return r; }
static int ctapi_transmit(sc_reader_t *reader, sc_apdu_t *apdu) { size_t ssize, rsize, rbuflen = 0; u8 *sbuf = NULL, *rbuf = NULL; int r; rsize = rbuflen = apdu->resplen + 2; rbuf = malloc(rbuflen); if (rbuf == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto out; } /* encode and log the APDU */ r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW); if (r != SC_SUCCESS) goto out; sc_apdu_log(reader->ctx, SC_LOG_DEBUG_NORMAL, sbuf, ssize, 1); r = ctapi_internal_transmit(reader, sbuf, ssize, rbuf, &rsize, apdu->control); if (r < 0) { /* unable to transmit ... most likely a reader problem */ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "unable to transmit"); goto out; } sc_apdu_log(reader->ctx, SC_LOG_DEBUG_NORMAL, rbuf, rsize, 0); /* set response */ r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize); out: if (sbuf != NULL) { sc_mem_clear(sbuf, ssize); free(sbuf); } if (rbuf != NULL) { sc_mem_clear(rbuf, rbuflen); free(rbuf); } return r; }
static int entersafe_mac_apdu(sc_card_t *card, sc_apdu_t *apdu, u8 * key,size_t keylen, u8 * buff,size_t buffsize) { int r; u8 iv[8]; u8 *tmp=0,*tmp_rounded=NULL; size_t tmpsize=0,tmpsize_rounded=0; int outl=0; EVP_CIPHER_CTX ctx; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); assert(card); assert(apdu); assert(key); assert(buff); if(apdu->cse != SC_APDU_CASE_3_SHORT) return SC_ERROR_INTERNAL; if(keylen!=8 && keylen!=16) return SC_ERROR_INTERNAL; r=entersafe_gen_random(card,iv,sizeof(iv)); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,r,"entersafe gen random failed"); /* encode the APDU in the buffer */ if ((r=sc_apdu_get_octets(card->ctx, apdu, &tmp, &tmpsize,SC_PROTO_RAW)) != SC_SUCCESS) goto out; /* round to 8 */ tmpsize_rounded=(tmpsize/8+1)*8; tmp_rounded = malloc(tmpsize_rounded); if (tmp_rounded == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto out; } /*build content and padded buffer by 0x80 0x00 0x00..... */ memset(tmp_rounded,0,tmpsize_rounded); memcpy(tmp_rounded,tmp,tmpsize); tmp_rounded[4]+=4; tmp_rounded[tmpsize]=0x80; /* block_size-1 blocks*/ EVP_CIPHER_CTX_init(&ctx); EVP_CIPHER_CTX_set_padding(&ctx,0); EVP_EncryptInit_ex(&ctx, EVP_des_cbc(), NULL, key, iv); if(tmpsize_rounded>8){ if(!EVP_EncryptUpdate(&ctx,tmp_rounded,&outl,tmp_rounded,tmpsize_rounded-8)){ r = SC_ERROR_INTERNAL; goto out; } } /* last block */ if(keylen==8) { if(!EVP_EncryptUpdate(&ctx,tmp_rounded+outl,&outl,tmp_rounded+outl,8)){ r = SC_ERROR_INTERNAL; goto out; } } else { EVP_EncryptInit_ex(&ctx, EVP_des_ede_cbc(), NULL, key,tmp_rounded+outl-8); if(!EVP_EncryptUpdate(&ctx,tmp_rounded+outl,&outl,tmp_rounded+outl,8)){ r = SC_ERROR_INTERNAL; goto out; } } if (!EVP_CIPHER_CTX_cleanup(&ctx)){ r = SC_ERROR_INTERNAL; goto out; } memcpy(buff,apdu->data,apdu->lc); /* use first 4 bytes of last block as mac value*/ memcpy(buff+apdu->lc,tmp_rounded+tmpsize_rounded-8,4); apdu->data=buff; apdu->lc+=4; apdu->datalen=apdu->lc; out: if(tmp) free(tmp); if(tmp_rounded) free(tmp_rounded); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); }
static int boxing_pin_cmd_to_buf(sc_context_t *ctx, const struct sc_pin_cmd_data *data, unsigned char **pc_to_rdr_secure, size_t *pc_to_rdr_secure_len) { PC_to_RDR_Secure_t *secure; abPINDataStucture_Modification_t *modify; abPINDataStucture_Verification_t *verify; uint16_t wLangId = 0, bTeoPrologue2 = 0, wPINMaxExtraDigit; uint8_t bTimeOut = CCID_PIN_TIMEOUT, bNumberMessage = CCID_DISPLAY_DEFAULT, bTeoPrologue1 = 0, bMsgIndex = 0, bMessageType = 0x69, bSlot = 0, bSeq = 0, bBWI = 0xff, wLevelParameter = 0, bEntryValidationCondition = CCID_ENTRY_VALIDATE, bmFormatString, bmPINLengthFormat, bmPINBlockString; const struct sc_pin_cmd_pin *pin_ref; int r; unsigned char *pinapdu = NULL; size_t pinapdu_len = 0; if (!data || !pc_to_rdr_secure || !pc_to_rdr_secure_len) { r = SC_ERROR_INVALID_ARGUMENTS; goto err; } pin_ref = data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? &data->pin2 : &data->pin1; wPINMaxExtraDigit = htole16( (0xff & pin_ref->min_length) << 8) | (pin_ref->max_length & 0xff); bmFormatString = CCID_PIN_UNITS_BYTES | ((pin_ref->offset & 0xf) << 3); switch (pin_ref->encoding) { case SC_PIN_ENCODING_ASCII: bmFormatString |= CCID_PIN_ENCODING_ASCII; break; case SC_PIN_ENCODING_BCD: bmFormatString |= CCID_PIN_ENCODING_BCD; break; default: r = SC_ERROR_INVALID_ARGUMENTS; goto err; } /* GLP PINs expect the effective PIN length from bit 4 */ bmPINLengthFormat = pin_ref->encoding == SC_PIN_ENCODING_GLP ? 0x04 : 0x00; if (pin_ref->encoding == SC_PIN_ENCODING_GLP) { /* GLP PIN length is encoded in 4 bits and block size is always 8 bytes */ bmPINBlockString = 0x40 | 0x08; } else if (pin_ref->encoding == SC_PIN_ENCODING_ASCII && data->flags & SC_PIN_CMD_NEED_PADDING) { bmPINBlockString = pin_ref->pad_length; } else { bmPINBlockString = 0x00; } r = sc_apdu_get_octets(ctx, data->apdu, &pinapdu, &pinapdu_len, SC_PROTO_T1); if (r < 0) goto err; switch (data->cmd) { case SC_PIN_CMD_VERIFY: *pc_to_rdr_secure_len = sizeof *secure + 1 + sizeof *verify + pinapdu_len; break; case SC_PIN_CMD_CHANGE: *pc_to_rdr_secure_len = sizeof *secure + 1 + sizeof *modify + 3 + pinapdu_len; break; default: r = SC_ERROR_INVALID_ARGUMENTS; goto err; } *pc_to_rdr_secure = malloc(*pc_to_rdr_secure_len); if (!*pc_to_rdr_secure) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } secure = (PC_to_RDR_Secure_t *) *pc_to_rdr_secure; secure->bMessageType = bMessageType; secure->dwLength = htole32((*pc_to_rdr_secure_len) - sizeof *secure); secure->bSlot = bSlot; secure->bSeq = bSeq; secure->bBWI = bBWI; secure->wLevelParameter = wLevelParameter; switch (data->cmd) { case SC_PIN_CMD_VERIFY: /* bPINOperation */ *((*pc_to_rdr_secure) + sizeof *secure) = CCID_OPERATION_VERIFY; verify = (abPINDataStucture_Verification_t *) ((*pc_to_rdr_secure) + sizeof *secure + 1); verify->bTimeOut = bTimeOut; verify->bmFormatString = bmFormatString; verify->bmPINBlockString = bmPINBlockString; verify->bmPINLengthFormat = bmPINLengthFormat; verify->wPINMaxExtraDigit = wPINMaxExtraDigit; verify->bEntryValidationCondition = bEntryValidationCondition; verify->bNumberMessage = bNumberMessage; verify->wLangId = wLangId; verify->bMsgIndex = bMsgIndex; verify->bTeoPrologue1 = bTeoPrologue1; verify->bTeoPrologue2 = bTeoPrologue2; memcpy((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *verify, pinapdu, pinapdu_len); break; case SC_PIN_CMD_CHANGE: /* bPINOperation */ *((*pc_to_rdr_secure) + sizeof *secure) = CCID_OPERATION_MODIFY; modify = (abPINDataStucture_Modification_t *) ((*pc_to_rdr_secure) + sizeof *secure + 1); modify->bTimeOut = bTimeOut; modify->bmFormatString = bmFormatString; modify->bmPINBlockString = bmPINBlockString; modify->bmPINLengthFormat = bmPINLengthFormat; if (!(data->flags & SC_PIN_CMD_IMPLICIT_CHANGE) && data->pin1.offset) { modify->bInsertionOffsetOld = data->pin1.offset - 5; } else { modify->bInsertionOffsetOld = 0; } modify->bInsertionOffsetNew = data->pin2.offset ? data->pin2.offset - 5 : 0; modify->wPINMaxExtraDigit = wPINMaxExtraDigit; modify->bConfirmPIN = CCID_PIN_CONFIRM_NEW | (data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? 0 : CCID_PIN_INSERT_OLD); modify->bEntryValidationCondition = bEntryValidationCondition; modify->bNumberMessage = bNumberMessage; modify->wLangId = wLangId; modify->bMsgIndex1 = bMsgIndex; *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 0) = bTeoPrologue1; *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 1) = bTeoPrologue1; *((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 2) = bTeoPrologue1; memcpy((*pc_to_rdr_secure) + sizeof *secure + 1 + sizeof *modify + 3, pinapdu, pinapdu_len); break; default: r = SC_ERROR_INVALID_ARGUMENTS; goto err; } r = SC_SUCCESS; err: free(pinapdu); if (r < 0 && pc_to_rdr_secure && *pc_to_rdr_secure) { free(*pc_to_rdr_secure); *pc_to_rdr_secure = NULL; } return r; }