Example #1
0
static int format_data(sc_card_t *card, const struct iso_sm_ctx *ctx,
        const u8 *data, size_t datalen,
        struct sc_asn1_entry *formatted_encrypted_data_entry,
        u8 **formatted_data, size_t *formatted_data_len)
{
    int r;
    u8 *pad_data = NULL;
    size_t pad_data_len = 0;

    if (!ctx || !formatted_data || !formatted_data_len) {
        r = SC_ERROR_INVALID_ARGUMENTS;
        goto err;
    }

    r = add_padding(ctx, data, datalen, &pad_data);
    if (r < 0) {
        sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not add padding to data: %s",
                sc_strerror(r));
        goto err;
    }
    pad_data_len = r;

    bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Data to encrypt", pad_data, pad_data_len);
    r = ctx->encrypt(card, ctx, pad_data, pad_data_len, formatted_data);
    if (r < 0) {
        sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not encrypt the data");
        goto err;
    }
    bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Cryptogram", *formatted_data, r);

    r = prefix_buf(ctx->padding_indicator, *formatted_data, r, formatted_data);
    if (r < 0) {
        sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not prepend padding indicator to formatted "
                "data: %s", sc_strerror(r));
        goto err;
    }

    *formatted_data_len = r;
    sc_format_asn1_entry(formatted_encrypted_data_entry,
            *formatted_data, formatted_data_len, SC_ASN1_PRESENT);

    r = SC_SUCCESS;

err:
    if (pad_data) {
        sc_mem_clear(pad_data, pad_data_len);
        free(pad_data);
    }

    return r;
}
Example #2
0
int npa_translate_apdus(sc_card_t *card, FILE *input)
{
    u8 buf[4 + 3 + 0xffff + 3];
    char *read = NULL;
    size_t readlen = 0, apdulen;
    sc_apdu_t apdu;
    ssize_t linelen;
    int r;

    memset(&apdu, 0, sizeof apdu);

    while (1) {
        if (input == stdin)
            printf("Enter unencrypted C-APDU (empty line to exit)\n");

        linelen = getline(&read, &readlen, input);
        if (linelen <= 1) {
            if (linelen < 0) {
                r = SC_ERROR_INTERNAL;
                sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,
                        "Could not read line");
            } else {
                r = SC_SUCCESS;
                printf("Thanks for flying with ccid\n");
            }
            break;
        }
        read[linelen - 1] = 0;

        apdulen = sizeof buf;
        if (sc_hex_to_bin(read, buf, &apdulen) < 0) {
            sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,
                    "Could not format binary string");
            continue;
        }
        if (input != stdin)
            bin_print(stdout, "Unencrypted C-APDU", buf, apdulen);

        r = sc_bytes2apdu(card->ctx, buf, apdulen, &apdu);
        if (r < 0) {
            bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Invalid C-APDU", buf, apdulen);
            continue;
        }

        apdu.resp = buf;
        apdu.resplen = sizeof buf;

        r = sc_transmit_apdu(card, &apdu);
        if (r < 0) {
            sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,
                    "Could not send C-APDU: %s", sc_strerror(r));
            continue;
        }

        printf("Decrypted R-APDU sw1=%02x sw2=%02x\n", apdu.sw1, apdu.sw2);
        bin_print(stdout, "Decrypted R-APDU response data", apdu.resp, apdu.resplen);
        printf("======================================================================\n");
    }

    if (read)
        free(read);

    return r;
}
Example #3
0
static int sm_decrypt(const struct iso_sm_ctx *ctx, sc_card_t *card,
        const sc_apdu_t *sm_apdu, sc_apdu_t *apdu)
{
    int r;
    struct sc_asn1_entry sm_rapdu[4];
    struct sc_asn1_entry my_sm_rapdu[4];
    u8 sw[2], mac[8], fdata[SC_MAX_EXT_APDU_BUFFER_SIZE];
    size_t sw_len = sizeof sw, mac_len = sizeof mac, fdata_len = sizeof fdata,
           buf_len, asn1_len;
    const u8 *buf;
    u8 *data = NULL, *mac_data = NULL, *asn1 = NULL;

    sc_copy_asn1_entry(c_sm_rapdu, sm_rapdu);
    sc_format_asn1_entry(sm_rapdu + 0, fdata, &fdata_len, 0);
    sc_format_asn1_entry(sm_rapdu + 1, sw, &sw_len, 0);
    sc_format_asn1_entry(sm_rapdu + 2, mac, &mac_len, 0);

    r = sc_asn1_decode(card->ctx, sm_rapdu, sm_apdu->resp, sm_apdu->resplen,
            &buf, &buf_len);
    if (r < 0)
        goto err;
    if (buf_len > 0) {
        r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
        goto err;
    }


    if (sm_rapdu[2].flags & SC_ASN1_PRESENT) {
        /* copy from sm_apdu to my_sm_apdu, but leave mac at default */
        sc_copy_asn1_entry(sm_rapdu, my_sm_rapdu);
        sc_copy_asn1_entry(&c_sm_rapdu[2], &my_sm_rapdu[2]);

        r = sc_asn1_encode(card->ctx, my_sm_rapdu, &asn1, &asn1_len);
        if (r < 0)
            goto err;
        r = add_padding(ctx, asn1, asn1_len, &mac_data);
        if (r < 0) {
            goto err;
        }
        
        r = ctx->verify_authentication(card, ctx, mac, mac_len,
                mac_data, r);
        if (r < 0)
            goto err;
    } else {
        sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Cryptographic Checksum missing");
        r = SC_ERROR_ASN1_OBJECT_NOT_FOUND;
        goto err;
    }


    if (sm_rapdu[0].flags & SC_ASN1_PRESENT) {
        if (ctx->padding_indicator != fdata[0]) {
            r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
            goto err;
        }
        r = ctx->decrypt(card, ctx, fdata + 1, fdata_len - 1, &data);
        if (r < 0)
            goto err;
        buf_len = r;

        r = rm_padding(ctx->padding_indicator, data, buf_len);
        if (r < 0) {
            sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not remove padding");
            goto err;
        }

        if (apdu->resplen < r || (r && !apdu->resp)) {
            sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
                    "Response of SM APDU %u byte%s too long", r-apdu->resplen,
                    r-apdu->resplen < 2 ? "" : "s");
            r = SC_ERROR_OUT_OF_MEMORY;
            goto err;
        }
        /* Flawfinder: ignore */
        memcpy(apdu->resp, data, r);
        apdu->resplen = r;
    } else {
        apdu->resplen = 0;
    }

    if (sm_rapdu[1].flags & SC_ASN1_PRESENT) {
        if (sw_len != 2) {
            sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Length of processing status bytes must be 2");
            r = SC_ERROR_ASN1_END_OF_CONTENTS;
            goto err;
        }
        apdu->sw1 = sw[0];
        apdu->sw2 = sw[1];
    } else {
        sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Authenticated status bytes are missing");
        r = SC_ERROR_ASN1_OBJECT_NOT_FOUND;
        goto err;
    }

    sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Decrypted APDU sw1=%02x sw2=%02x",
            apdu->sw1, apdu->sw2);
    bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Decrypted APDU response data",
            apdu->resp, apdu->resplen);

    r = SC_SUCCESS;

err:
    free(asn1);
    free(mac_data);
    if (data) {
        sc_mem_clear(data, buf_len);
        free(data);
    }

    return r;
}
Example #4
0
static int sm_encrypt(const struct iso_sm_ctx *ctx, sc_card_t *card,
        const sc_apdu_t *apdu, sc_apdu_t **psm_apdu)
{
    struct sc_asn1_entry sm_capdu[4];
    u8 *p, *le = NULL, *sm_data = NULL, *fdata = NULL, *mac_data = NULL,
       *asn1 = NULL, *mac = NULL, *resp_data = NULL;
    size_t sm_data_len, fdata_len, mac_data_len, asn1_len, mac_len, le_len;
    int r, cse;
    sc_apdu_t *sm_apdu = NULL;

    if (!apdu || !ctx || !card || !card->reader || !psm_apdu) {
        r = SC_ERROR_INVALID_ARGUMENTS;
        goto err;
    }

    if ((apdu->cla & 0x0C) == 0x0C) {
        r = SC_ERROR_INVALID_ARGUMENTS;
        sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Given APDU is already protected with some secure messaging");
        goto err;
    }

    sc_copy_asn1_entry(c_sm_capdu, sm_capdu);

    sm_apdu = malloc(sizeof(sc_apdu_t));
    if (!sm_apdu) {
        r = SC_ERROR_OUT_OF_MEMORY;
        goto err;
    }
    sm_apdu->control = apdu->control;
    sm_apdu->flags = apdu->flags;
    sm_apdu->cla = apdu->cla|0x0C;
    sm_apdu->ins = apdu->ins;
    sm_apdu->p1 = apdu->p1;
    sm_apdu->p2 = apdu->p2;
    r = format_head(ctx, sm_apdu, &mac_data);
    if (r < 0) {
        sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format header of SM apdu");
        goto err;
    }
    mac_data_len = r;

    /* get le and data depending on the case of the insecure command */
    cse = apdu->cse;
    if ((apdu->le/ctx->block_length + 1)*ctx->block_length + 18 > 0xff+1)
        /* for encrypted APDUs we usually get authenticated status bytes (4B),
         * a MAC (11B) and a cryptogram with padding indicator (3B without
         * data).  The cryptogram is always padded to the block size. */
        cse |= SC_APDU_EXT;

    switch (cse) {
        case SC_APDU_CASE_1:
            break;
	case SC_APDU_CASE_2_SHORT:
            le_len = 1;
            r = format_le(apdu->le, sm_capdu + 1, &le, &le_len);
            if (r < 0) {
                sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu");
                goto err;
            }
            bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Protected Le (plain)", le, le_len);
            break;
	case SC_APDU_CASE_2_EXT:
            if (card->reader->active_protocol == SC_PROTO_T0) {
                /* T0 extended APDUs look just like short APDUs */
                le_len = 1;
                r = format_le(apdu->le, sm_capdu + 1, &le, &le_len);
                if (r < 0) {
                    sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu");
                    goto err;
                }
            } else {
                /* in case of T1 always use 2 bytes for length */
                le_len = 2;
                r = format_le(apdu->le, sm_capdu + 1, &le, &le_len);
                if (r < 0) {
                    sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu");
                    goto err;
                }
            }
            bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Protected Le (plain)", le, le_len);
            break;
        case SC_APDU_CASE_3_SHORT:
        case SC_APDU_CASE_3_EXT:
            r = format_data(card, ctx, apdu->data, apdu->datalen,
                    sm_capdu + 0, &fdata, &fdata_len);
            if (r < 0) {
                sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu");
                goto err;
            }
            bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Padding-content indicator followed by cryptogram (plain)",
                    fdata, fdata_len);
            break;
        case SC_APDU_CASE_4_SHORT:
            /* in case of T0 no Le byte is added */
            if (card->reader->active_protocol != SC_PROTO_T0) {
                le_len = 1;
                r = format_le(apdu->le, sm_capdu + 1, &le, &le_len);
                if (r < 0) {
                    sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu");
                    goto err;
                }
                bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Protected Le (plain)", le, le_len);
            }

            r = format_data(card, ctx, apdu->data, apdu->datalen,
                    sm_capdu + 0, &fdata, &fdata_len);
            if (r < 0) {
                sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu");
                goto err;
            }
            bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Padding-content indicator followed by cryptogram (plain)",
                    fdata, fdata_len);
            break;
        case SC_APDU_CASE_4_EXT:
            if (card->reader->active_protocol == SC_PROTO_T0) {
                /* again a T0 extended case 4 APDU looks just
                 * like a short APDU, the additional data is
                 * transferred using ENVELOPE and GET RESPONSE */
            } else {
                /* only 2 bytes are use to specify the length of the
                 * expected data */
                le_len = 2;
                r = format_le(apdu->le, sm_capdu + 1, &le, &le_len);
                if (r < 0) {
                    sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu");
                    goto err;
                }
                bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Protected Le (plain)", le, le_len);
            }

            r = format_data(card, ctx, apdu->data, apdu->datalen,
                    sm_capdu + 0, &fdata, &fdata_len);
            if (r < 0) {
                sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu");
                goto err;
            }
            bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Padding-content indicator followed by cryptogram (plain)",
                    fdata, fdata_len);
            break;
        default:
            sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Unhandled apdu case");
            r = SC_ERROR_INVALID_DATA;
            goto err;
    }


    r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &asn1, &asn1_len);
    if (r < 0) {
        goto err;
    }
    if (asn1_len) {
        p = realloc(mac_data, mac_data_len + asn1_len);
        if (!p) {
            r = SC_ERROR_OUT_OF_MEMORY;
            goto err;
        }
        mac_data = p;
        /* Flawfinder: ignore */
        memcpy(mac_data + mac_data_len, asn1, asn1_len);
        mac_data_len += asn1_len;
        r = add_padding(ctx, mac_data, mac_data_len, &mac_data);
        if (r < 0) {
            goto err;
        }
        mac_data_len = r;
    }
    bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Data to authenticate", mac_data, mac_data_len);

    r = ctx->authenticate(card, ctx, mac_data, mac_data_len,
            &mac);
    if (r < 0) {
        sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get authentication code");
        goto err;
    }
    mac_len = r;
    bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Cryptographic Checksum (plain)", mac, mac_len);


    /* format SM apdu */
    sc_format_asn1_entry(sm_capdu + 2, mac, &mac_len, SC_ASN1_PRESENT);
    r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &sm_data, &sm_data_len);
    if (r < 0)
        goto err;
    sm_apdu->data = sm_data;
    sm_apdu->datalen = sm_data_len;
    sm_apdu->lc = sm_data_len;
    sm_apdu->le = 0;
    if (cse & SC_APDU_EXT) {
        sm_apdu->cse = SC_APDU_CASE_4_EXT;
#if OPENSC_NOT_BOGUS_ANYMORE
        sm_apdu->resplen = 0xffff+1;
#else
        sm_apdu->resplen = SC_MAX_EXT_APDU_BUFFER_SIZE;
#endif
    } else {
        sm_apdu->cse = SC_APDU_CASE_4_SHORT;
#if OPENSC_NOT_BOGUS_ANYMORE
        sm_apdu->resplen = 0xff+1;
#else
        sm_apdu->resplen = SC_MAX_APDU_BUFFER_SIZE;
#endif
    }
    resp_data = malloc(sm_apdu->resplen);
    if (!resp_data) {
        r = SC_ERROR_OUT_OF_MEMORY;
        goto err;
    }
    sm_apdu->resp = resp_data;
    bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ASN.1 encoded encrypted APDU data", sm_apdu->data, sm_apdu->datalen);

    *psm_apdu = sm_apdu;

err:
    free(fdata);
    free(asn1);
    free(mac_data);
    free(mac);
    free(le);
    if (r < 0) {
        free(resp_data);
        free(sm_apdu);
        free(sm_data);
    }

    return r;
}