Example #1
0
/*
 * Create an empty security environment
 */
static int
incrypto34_create_sec_env(struct sc_profile *profile, struct sc_card *card,
		unsigned int se_id, unsigned int key_id)
{
	struct sc_cardctl_incrypto34_obj_info args;
	struct tlv	tlv;
	unsigned char	buffer[64];

	tlv_init(&tlv, buffer, sizeof(buffer));
	tlv_next(&tlv, 0x83);
	tlv_add(&tlv, se_id);

	tlv_next(&tlv, 0x86);
	tlv_add(&tlv, 0);
	tlv_add(&tlv, 0);

	tlv_next(&tlv, 0x8f);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);

	args.data = buffer;
	args.len = tlv_len(&tlv);
	return sc_card_ctl(card, SC_CARDCTL_INCRYPTO34_PUT_DATA_SECI, &args);
}
Example #2
0
/*
 * Create an empty security environment
 */
static int
cardos_create_sec_env(struct sc_profile *profile, sc_card_t *card,
		unsigned int se_id, unsigned int key_id)
{
	struct sc_cardctl_cardos_obj_info args;
	struct tlv	tlv;
	unsigned char	buffer[64];
	int		r;

	tlv_init(&tlv, buffer, sizeof(buffer));
	tlv_next(&tlv, 0x83);
	tlv_add(&tlv, se_id);

	tlv_next(&tlv, 0x86);
	tlv_add(&tlv, 0);
	tlv_add(&tlv, 0);

	tlv_next(&tlv, 0x8f);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);
	tlv_add(&tlv, key_id);

	args.data = buffer;
	args.len = tlv_len(&tlv);

	/* ensure we are in the correct lifecycle */
	r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
	if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
		return r;

	return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_SECI, &args);
}
Example #3
0
File: tlv.c Project: dtaht/hnetd
void *
tlv_nest_start(struct tlv_buf *buf, int id, int len)
{
	unsigned long offset = attr_to_offset(buf, buf->head);
	buf->head = tlv_add(buf, tlv_next(buf->head), id, len);
	return (void *) offset;
}
Example #4
0
/*
 * Full-length of all TLV fields.
 */
size_t
tlv_sequence_length (uint8_t *stream)
{
    size_t res = 0;

    do {
        res += tlv_record_length (stream, NULL, NULL);
    } while ((stream = tlv_next (stream)));

    return res;
}
Example #5
0
File: tlv.c Project: dtaht/hnetd
struct tlv_attr *
tlv_new(struct tlv_buf *buf, int id, int payload)
{
	struct tlv_attr *attr;

	attr = tlv_add(buf, tlv_next(buf->head), id, payload);
	if (!attr)
		return NULL;

	tlv_set_raw_len(buf->head, tlv_pad_len(buf->head) + tlv_pad_len(attr));
	return attr;
}
Example #6
0
static struct tlv *
qmi_tlv_next (QmiMessage *self,
              struct tlv *tlv)
{
    struct tlv *end;
    struct tlv *next;

    end = (struct tlv *) qmi_end (self);
    next = tlv_next (tlv);

    return (next < end ? next : NULL);
}
Example #7
0
File: tlv.c Project: dtaht/hnetd
struct tlv_attr *
tlv_put_raw(struct tlv_buf *buf, const void *ptr, int len)
{
	struct tlv_attr *attr;

	if (len < (int)sizeof(struct tlv_attr) || !ptr)
		return NULL;

	attr = tlv_add(buf, tlv_next(buf->head), 0, len - sizeof(struct tlv_attr));
	tlv_set_raw_len(buf->head, tlv_pad_len(buf->head) + len);
	memcpy(attr, ptr, len);
	return attr;
}
Example #8
0
static int
cardos_store_key_component(sc_card_t *card,
		int algorithm,
		unsigned int key_id, unsigned int pin_id,
		unsigned int num,
		const u8 *data, size_t len,
		int last, int use_prefix)
{
	struct sc_cardctl_cardos_obj_info args;
	struct tlv	tlv;
	unsigned char	buffer[256];
#ifdef SET_SM_BYTES
	unsigned int	n;
#endif
	int		r;

	/* Initialize the TLV encoder */
	tlv_init(&tlv, buffer, sizeof(buffer));

	/* Object address */
	tlv_next(&tlv, 0x83);
	tlv_add(&tlv, 0x20|num);	/* PSO, n-th component */
	tlv_add(&tlv, key_id);

	/* Object parameters */
	tlv_next(&tlv, 0x85);
	tlv_add(&tlv, CARDOS_KEY_OPTIONS|(last? 0x00 : 0x20));
	tlv_add(&tlv, CARDOS_KEY_FLAGS);
	tlv_add(&tlv, algorithm);
	tlv_add(&tlv, 0x00);
	tlv_add(&tlv, 0xFF);	/* use count */
	tlv_add(&tlv, 0xFF);	/* DEK (whatever this is) */
	tlv_add(&tlv, 0x00);
	tlv_add(&tlv, 0x00);

	/* AC bytes */
	tlv_next(&tlv, 0x86);
	tlv_add(&tlv, pin_id);	/* AC USE */
	tlv_add(&tlv, pin_id);	/* AC CHANGE */
	tlv_add(&tlv, pin_id);	/* UNKNOWN */
	tlv_add(&tlv, 0);	/* rfu */
	tlv_add(&tlv, 0);	/* rfu */
	tlv_add(&tlv, 0);	/* rfu */
#if 0
	tlv_add(&tlv, pin_id);	/* AC GENKEY */
#else
	tlv_add(&tlv, 0);
#endif

#ifdef SET_SM_BYTES
	/* it shouldn't be necessary to set the default value */
	/* SM bytes */
	tlv_next(&tlv, 0x8B);
	for (n = 0; n < 16; n++)
		tlv_add(&tlv, 0xFF);
#endif

	/* key component */
	tlv_next(&tlv, 0x8f);
	if (use_prefix != 0) {
		tlv_add(&tlv, len+1);
		tlv_add(&tlv, 0);
	}
	while (len--)
		tlv_add(&tlv, *data++);

	args.data = buffer;
	args.len = tlv_len(&tlv);

	/* ensure we are in the correct lifecycle */
	r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
	if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
		return r;

	return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_OCI, &args);
}
Example #9
0
/*
 * Store a PIN or PUK
 */
static int
cardos_store_pin(sc_profile_t *profile, sc_card_t *card,
		sc_pkcs15_pin_info_t *pin_info, int puk_id,
		const u8 *pin, size_t pin_len)
{
	struct sc_cardctl_cardos_obj_info args;
	unsigned char	buffer[256];
	unsigned char	pinpadded[256];
	struct tlv	tlv;
	unsigned int	attempts, minlen, maxlen;
	int		r;

	/* We need to do padding because pkcs15-lib.c does it.
	 * Would be nice to have a flag in the profile that says
	 * "no padding required". */
	maxlen = MIN(profile->pin_maxlen, sizeof(pinpadded));
	if (pin_len > maxlen) {
		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "invalid pin length: %u (max %u)\n",
		         pin_len, maxlen);
		return SC_ERROR_INVALID_ARGUMENTS;
	}
	memcpy(pinpadded, pin, pin_len);
	while (pin_len < maxlen)
		pinpadded[pin_len++] = profile->pin_pad_char;
	pin = pinpadded;

	attempts = pin_info->tries_left;
	minlen = pin_info->min_length;

	tlv_init(&tlv, buffer, sizeof(buffer));

	/* object address: class, id */
	tlv_next(&tlv, 0x83);
	tlv_add(&tlv, 0x00);		/* class byte: usage TEST, k=0 */
	tlv_add(&tlv, pin_info->reference);

	/* parameters */
	tlv_next(&tlv, 0x85);
	tlv_add(&tlv, 0x02);		/* options byte */
	tlv_add(&tlv, attempts & 0xf);	/* flags byte */
	tlv_add(&tlv, CARDOS_ALGO_PIN);	/* algorithm = pin-test */
	tlv_add(&tlv, attempts & 0xf);	/* errcount = attempts */

	/* usecount: not documented, but seems to work like this:
	 *  -	value of 0xff means pin can be presented any number
	 *	of times
	 *  -	anything less: max # of times before BS object is blocked.
	 */
	tlv_add(&tlv, 0xff);

	/* DEK: not documented, no idea what it means */
	tlv_add(&tlv, 0xff);

	/* ARA counter: number of times the test object can be used before
	 *              another verification is required (~ user consent)
	 *              (0x00 unlimited usage)
	 */
	tlv_add(&tlv, 0x00);

	tlv_add(&tlv, minlen);			/* minlen */

	/* AC conditions */
	tlv_next(&tlv, 0x86);
	tlv_add(&tlv, 0x00);			/* use: always */
	tlv_add(&tlv, pin_info->reference);	/* change: PIN */
	tlv_add(&tlv, puk_id);			/* unblock: PUK */

	/* data: PIN */
	tlv_next(&tlv, 0x8f);
	while (pin_len--)
		tlv_add(&tlv, *pin++);

	args.data = buffer;
	args.len = tlv_len(&tlv);

	/* ensure we are in the correct lifecycle */
	r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
	if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
		return r;

	return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_OCI, &args);
}
Example #10
0
static int
incrypto34_store_key_component(struct sc_card *card,
		int algorithm,
		unsigned int key_id, unsigned int pin_id,
		unsigned int num,
		const u8 *data, size_t len,
		int last)
{
	int	r;
	struct sc_cardctl_incrypto34_obj_info args;
	struct tlv	tlv;
	unsigned char	buffer[256];
	unsigned int	n;

	/* Initialize the TLV encoder */
	tlv_init(&tlv, buffer, sizeof(buffer));

	/* Object address */
	tlv_next(&tlv, 0x83);
	tlv_add(&tlv, 0x20|num);	/* PSO, n-th component */
	tlv_add(&tlv, key_id);

	/* Object parameters */
	tlv_next(&tlv, 0x85);
	tlv_add(&tlv, INCRYPTO34_KEY_OPTIONS|(last? 0x00 : 0x20));
	tlv_add(&tlv, INCRYPTO34_KEY_FLAGS);
	tlv_add(&tlv, algorithm);
	tlv_add(&tlv, 0x0F);    /* Error Counter*/
	tlv_add(&tlv, 0xFF);	/* use count */
	tlv_add(&tlv, 0xFF);	/* RFU */
	tlv_add(&tlv, 0x00);    /* RFU */
	tlv_add(&tlv, 0x00);    /* RFU */

	/* AC bytes */
	tlv_next(&tlv, 0x86);
	tlv_add(&tlv, pin_id);	/* AC USE */
	tlv_add(&tlv, pin_id);	/* AC CHANGE */
	tlv_add(&tlv, 0xFF);	/* AC_UNBLOCK */
	tlv_add(&tlv, 0xFF);	/* RFU */
	tlv_add(&tlv, 0xFF);    /* RFU */
	tlv_add(&tlv, 0xFF);	/* RFU */
	tlv_add(&tlv, 0);  /* AC_GENKEY */
	tlv_add(&tlv, 0xFF);    /* RFU */
	tlv_add(&tlv, 0xFF);    /* RFU */
	tlv_add(&tlv, 0xFF);    /* RFU */

	/* SM bytes */
	tlv_next(&tlv, 0x8B);
	for (n = 0; n < 16; n++)
		tlv_add(&tlv, 0xFF);

	/* key component */
	tlv_next(&tlv, 0x8f);
	tlv_add(&tlv, len+1);
	tlv_add(&tlv, 0);
	while (len--)
		tlv_add(&tlv, *data++);


	args.data = buffer;
	args.len = tlv_len(&tlv);
	r = sc_card_ctl(card, SC_CARDCTL_INCRYPTO34_PUT_DATA_OCI, &args);
	return r;
}
Example #11
0
/*
 * Store a PIN or PUK
 */
static int
incrypto34_store_pin(sc_profile_t *profile, sc_card_t *card,
		sc_pkcs15_auth_info_t *auth_info, int puk_id,
		const u8 *pin, size_t pin_len)
{
	struct sc_cardctl_incrypto34_obj_info args;
	unsigned char	buffer[256];
	unsigned char	pinpadded[16];
	struct tlv	tlv;
	unsigned int	attempts, minlen, maxlen;

	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
		return SC_ERROR_OBJECT_NOT_VALID;

	/* We need to do padding because pkcs15-lib.c does it.
	 * Would be nice to have a flag in the profile that says
	 * "no padding required". */
	maxlen = MIN(profile->pin_maxlen, sizeof(pinpadded));
	if (pin_len > maxlen)
		pin_len = maxlen;
	memcpy(pinpadded, pin, pin_len);
	while (pin_len < maxlen)
		pinpadded[pin_len++] = profile->pin_pad_char;
	pin = pinpadded;

	attempts = auth_info->tries_left;
	minlen = auth_info->attrs.pin.min_length;

	tlv_init(&tlv, buffer, sizeof(buffer));

	/* object address: class, id */
	tlv_next(&tlv, 0x83);
	tlv_add(&tlv, 0x00);		/* class byte: usage TEST, k=0 */
	tlv_add(&tlv, auth_info->attrs.pin.reference);

	/* parameters */
	tlv_next(&tlv, 0x85);
	tlv_add(&tlv, 0x02);		/* options byte */
	tlv_add(&tlv, attempts & 0xf);	/* flags byte */
	tlv_add(&tlv, INCRYPTO34_ALGO_PIN);	/* algorithm = pin-test */
	tlv_add(&tlv, attempts & 0xf);	/* errcount = attempts */

	/* usecount: not documented, but seems to work like this:
	 *  -	value of 0xff means pin can be presented any number
	 *	of times
	 *  -	anything less: max # of times before BS object is blocked.
	 */
	tlv_add(&tlv, 0xff);

	/* DEK: RFU */
	tlv_add(&tlv, 0x00);

	/* ARA counter: the number of times the PIN can be used before the he must be verified
	again (0 or ff for unlimited usage) */
	tlv_add(&tlv, 0x00);

	tlv_add(&tlv, minlen);			/* minlen */

	/* AC conditions */
	tlv_next(&tlv, 0x86);
	tlv_add(&tlv, 0x00);			/* use: always */
	tlv_add(&tlv, auth_info->attrs.pin.reference);	/* change: PIN */
	tlv_add(&tlv, puk_id);			/* unblock: PUK */
	tlv_add(&tlv, 0xFF);			/*RFU*/
	tlv_add(&tlv, 0xFF);			/*RFU*/
	tlv_add(&tlv, 0xFF);			/*RFU*/
	tlv_add(&tlv, 0xFF);			/*unused on pins*/
	tlv_add(&tlv, 0xFF);			/*RFU*/
	tlv_add(&tlv, 0xFF);			/*RFU*/
	tlv_add(&tlv, 0xFF);			/*RFU*/


	/* data: PIN */
	tlv_next(&tlv, 0x8f);
	while (pin_len--)
		tlv_add(&tlv, *pin++);

	args.data = buffer;
	args.len = tlv_len(&tlv);

	return sc_card_ctl(card, SC_CARDCTL_INCRYPTO34_PUT_DATA_OCI, &args);
}
Example #12
0
/**
 * Checks the validity of a QMI message.
 *
 * In particular, checks:
 * 1. The message has space for all required headers.
 * 2. The length of the buffer, the qmux length field, and the QMI tlv_length
 *    field are all consistent.
 * 3. The TLVs in the message fit exactly in the payload size.
 *
 * Returns non-zero if the message is valid, zero if invalid.
 */
gboolean
qmi_message_check (QmiMessage *self,
                   GError **error)
{
    gsize header_length;
    gchar *end;
    struct tlv *tlv;

    g_assert (self != NULL);
    g_assert (self->buf != NULL);

    if (self->buf->marker != QMI_MESSAGE_QMUX_MARKER) {
        g_set_error (error,
                     QMI_CORE_ERROR,
                     QMI_CORE_ERROR_INVALID_MESSAGE,
                     "Marker is incorrect");
        return FALSE;
    }

    if (qmux_length (self) < sizeof (struct qmux)) {
        g_set_error (error,
                     QMI_CORE_ERROR,
                     QMI_CORE_ERROR_INVALID_MESSAGE,
                     "QMUX length too short for QMUX header (%u < %" G_GSIZE_FORMAT ")",
                     qmux_length (self), sizeof (struct qmux));
        return FALSE;
    }

    /*
     * qmux length is one byte shorter than buffer length because qmux
     * length does not include the qmux frame marker.
     */
    if (qmux_length (self) != self->len - 1) {
        g_set_error (error,
                     QMI_CORE_ERROR,
                     QMI_CORE_ERROR_INVALID_MESSAGE,
                     "QMUX length and buffer length don't match (%u != %" G_GSIZE_FORMAT ")",
                     qmux_length (self), self->len - 1);
        return FALSE;
    }

    header_length = sizeof (struct qmux) + (qmi_message_is_control (self) ?
                                            sizeof (struct control_header) :
                                            sizeof (struct service_header));

    if (qmux_length (self) < header_length) {
        g_set_error (error,
                     QMI_CORE_ERROR,
                     QMI_CORE_ERROR_INVALID_MESSAGE,
                     "QMUX length too short for QMI header (%u < %" G_GSIZE_FORMAT ")",
                     qmux_length (self), header_length);
        return FALSE;
    }

    if (qmux_length (self) - header_length != qmi_tlv_length (self)) {
        g_set_error (error,
                     QMI_CORE_ERROR,
                     QMI_CORE_ERROR_INVALID_MESSAGE,
                     "QMUX length and QMI TLV lengths don't match (%u - %" G_GSIZE_FORMAT " != %u)",
                     qmux_length (self), header_length, qmi_tlv_length (self));
        return FALSE;
    }

    end = qmi_end (self);
    for (tlv = qmi_tlv (self); tlv < (struct tlv *)end; tlv = tlv_next (tlv)) {
        if (tlv->value > end) {
            g_set_error (error,
                         QMI_CORE_ERROR,
                         QMI_CORE_ERROR_INVALID_MESSAGE,
                         "TLV header runs over buffer (%p > %p)",
                         tlv->value, end);
            return FALSE;
        }
        if (tlv->value + le16toh (tlv->length) > end) {
            g_set_error (error,
                         QMI_CORE_ERROR,
                         QMI_CORE_ERROR_INVALID_MESSAGE,
                         "TLV value runs over buffer (%p + %u  > %p)",
                         tlv->value, le16toh (tlv->length), end);
            return FALSE;
        }
    }

    /*
     * If this assert triggers, one of the if statements in the loop is wrong.
     * (It shouldn't be reached on malformed QMI messages.)
     */
    g_assert (tlv == (struct tlv *)end);

    return TRUE;
}