Add support for TLV streams.
- New API functions: tlv_encode(), tlv_decode(); - Documentation (man page); - Unit tests.
This commit is contained in:
parent
644a21ad9a
commit
b8049f110d
6 changed files with 358 additions and 4 deletions
|
@ -8,7 +8,8 @@ libfreefare_la_SOURCES = freefare.c \
|
||||||
mifare_classic.c \
|
mifare_classic.c \
|
||||||
mifare_ultralight.c \
|
mifare_ultralight.c \
|
||||||
mad.c \
|
mad.c \
|
||||||
mifare_application.c
|
mifare_application.c \
|
||||||
|
tlv.c
|
||||||
libfreefare_la_HEADERS = freefare.h
|
libfreefare_la_HEADERS = freefare.h
|
||||||
libfreefare_ladir = $(includedir)
|
libfreefare_ladir = $(includedir)
|
||||||
|
|
||||||
|
@ -16,7 +17,8 @@ man_MANS = freefare.3 \
|
||||||
mifare_ultralight.3 \
|
mifare_ultralight.3 \
|
||||||
mifare_classic.3 \
|
mifare_classic.3 \
|
||||||
mad.3 \
|
mad.3 \
|
||||||
mifare_application.3
|
mifare_application.3 \
|
||||||
|
tlv.3
|
||||||
|
|
||||||
linkedman = \
|
linkedman = \
|
||||||
freefare.3 freefare_get_tags.3 \
|
freefare.3 freefare_get_tags.3 \
|
||||||
|
@ -57,7 +59,9 @@ linkedman = \
|
||||||
mad.3 mad_free.3 \
|
mad.3 mad_free.3 \
|
||||||
mifare_application.3 mifare_application_alloc.3 \
|
mifare_application.3 mifare_application_alloc.3 \
|
||||||
mifare_application.3 mifare_application_free.3 \
|
mifare_application.3 mifare_application_free.3 \
|
||||||
mifare_application.3 mifare_application_find.3
|
mifare_application.3 mifare_application_find.3 \
|
||||||
|
tlv.3 tlv_encode.3 \
|
||||||
|
tlv.3 tlv_decode.3
|
||||||
|
|
||||||
install-data-hook:
|
install-data-hook:
|
||||||
(cd $(DESTDIR)$(man3dir); for i in `echo $(linkedman) | xargs -n2 echo | awk '{print $$2}'`; do rm -f $$i; done; echo $(linkedman) | xargs -n2 $(LN_S))
|
(cd $(DESTDIR)$(man3dir); for i in `echo $(linkedman) | xargs -n2 echo | awk '{print $$2}'`; do rm -f $$i; done; echo $(linkedman) | xargs -n2 $(LN_S))
|
||||||
|
|
|
@ -141,6 +141,10 @@ void mifare_application_free (Mad mad, MadAid aid);
|
||||||
|
|
||||||
MifareSectorNumber *mifare_application_find (Mad mad, MadAid aid);
|
MifareSectorNumber *mifare_application_find (Mad mad, MadAid aid);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t *tlv_encode (const uint8_t type, const uint8_t *istream, uint16_t isize, size_t *osize);
|
||||||
|
uint8_t *tlv_decode (const uint8_t *istream, uint8_t *type, uint16_t *size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
115
libfreefare/tlv.3
Normal file
115
libfreefare/tlv.3
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
.\" Copyright (C) 2010 Romain Tartiere
|
||||||
|
.\"
|
||||||
|
.\" This program is free software: you can redistribute it and/or modify it
|
||||||
|
.\" under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
.\" Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
.\" option) any later version.
|
||||||
|
.\"
|
||||||
|
.\" This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
.\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
.\" more details.
|
||||||
|
.\"
|
||||||
|
.\" You should have received a copy of the GNU Lesser General Public License
|
||||||
|
.\" along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
.\"
|
||||||
|
.\" $Id$
|
||||||
|
.\"
|
||||||
|
.Dd March 30, 2010
|
||||||
|
.Dt TLV 3
|
||||||
|
.Os
|
||||||
|
.\" _ _
|
||||||
|
.\" | \ | | __ _ _ __ ___ ___
|
||||||
|
.\" | \| |/ _` | '_ ` _ \ / _ \
|
||||||
|
.\" | |\ | (_| | | | | | | __/
|
||||||
|
.\" |_| \_|\__,_|_| |_| |_|\___|
|
||||||
|
.\"
|
||||||
|
.Sh NAME
|
||||||
|
.Nm tlv_encode ,
|
||||||
|
.Nm tlv_decode
|
||||||
|
.Nd TLV Manipulation Functions
|
||||||
|
.\" _ _ _
|
||||||
|
.\" | | (_) |__ _ __ __ _ _ __ _ _
|
||||||
|
.\" | | | | '_ \| '__/ _` | '__| | | |
|
||||||
|
.\" | |___| | |_) | | | (_| | | | |_| |
|
||||||
|
.\" |_____|_|_.__/|_| \__,_|_| \__, |
|
||||||
|
.\" |___/
|
||||||
|
.Sh LIBRARY
|
||||||
|
Mifare card manipulation library (libfreefare, \-lfreefare)
|
||||||
|
.\" ____ _
|
||||||
|
.\" / ___| _ _ _ __ ___ _ __ ___(_)___
|
||||||
|
.\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __|
|
||||||
|
.\" ___) | |_| | | | | (_) | |_) \__ \ \__ \
|
||||||
|
.\" |____/ \__, |_| |_|\___/| .__/|___/_|___/
|
||||||
|
.\" |___/ |_|
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.In freefare.h
|
||||||
|
.Ft "uint8_t *"
|
||||||
|
.Fn tlv_encode "const uint8_t type" "const uint8_t *istream" "uint16_t isize" "size_t *osize"
|
||||||
|
.Ft "uint8_t *"
|
||||||
|
.Fn tlv_decode "const uint8_t *istream" "const uint8_t *type" "uint16_t *size"
|
||||||
|
.\" ____ _ _ _
|
||||||
|
.\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __
|
||||||
|
.\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \
|
||||||
|
.\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | |
|
||||||
|
.\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_|
|
||||||
|
.\" |_|
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Fn tlv_encode
|
||||||
|
and
|
||||||
|
.Fn tlv_decode
|
||||||
|
functions are helpers to manipulate TLV (Text-Length-Value) data.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Fn tlv_encode
|
||||||
|
function converts the
|
||||||
|
.Ar isize
|
||||||
|
bytes long
|
||||||
|
.Ar istream
|
||||||
|
message into a TLV stream of type
|
||||||
|
.Ar type
|
||||||
|
and set the value of
|
||||||
|
.Ar osize
|
||||||
|
to the length of the returned stream.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Fn tlv_decode
|
||||||
|
function converts the
|
||||||
|
.Ar istream
|
||||||
|
TLV stream and set the
|
||||||
|
.Ar type
|
||||||
|
argument according to the type of the stream, and set the
|
||||||
|
.Ar size
|
||||||
|
argument to the length of the returned stream.
|
||||||
|
.\" ____ _ _
|
||||||
|
.\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___
|
||||||
|
.\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __|
|
||||||
|
.\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \
|
||||||
|
.\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/
|
||||||
|
.\"
|
||||||
|
.Sh RETURN VALUES
|
||||||
|
Both functions return memory allocated using
|
||||||
|
.Xr malloc 3
|
||||||
|
which should be reclaimed using
|
||||||
|
.Xr free 3
|
||||||
|
after usage.
|
||||||
|
.\" ____ _
|
||||||
|
.\" / ___| ___ ___ __ _| |___ ___
|
||||||
|
.\" \___ \ / _ \/ _ \ / _` | / __|/ _ \
|
||||||
|
.\" ___) | __/ __/ | (_| | \__ \ (_) |
|
||||||
|
.\" |____/ \___|\___| \__,_|_|___/\___/
|
||||||
|
.\"
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr freefare 3 ,
|
||||||
|
.Xr malloc 3 ,
|
||||||
|
.Xr free 3
|
||||||
|
.\" _ _ _
|
||||||
|
.\" / \ _ _| |_| |__ ___ _ __ ___
|
||||||
|
.\" / _ \| | | | __| '_ \ / _ \| '__/ __|
|
||||||
|
.\" / ___ \ |_| | |_| | | | (_) | | \__ \
|
||||||
|
.\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/
|
||||||
|
.\"
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An Romain Tartiere Aq romain@blogreen.org
|
||||||
|
.An Romuald Conty Aq rconty@il4p.fr
|
96
libfreefare/tlv.c
Normal file
96
libfreefare/tlv.c
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (C) 2010, Romain Tartiere, Romuald Conty.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <endian.h>
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TLV (Type Length Value) Manipulation Functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode data stream into TLV.
|
||||||
|
*/
|
||||||
|
uint8_t *
|
||||||
|
tlv_encode (const uint8_t type, const uint8_t *istream, uint16_t isize, size_t *osize)
|
||||||
|
{
|
||||||
|
uint8_t *res;
|
||||||
|
off_t n = 0;
|
||||||
|
|
||||||
|
if (osize)
|
||||||
|
*osize = 0;
|
||||||
|
|
||||||
|
if (isize == 0xffff) /* RFU */
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((res = malloc (1 + ((isize > 254) ? 3 : 1) + isize))) {
|
||||||
|
res[n++] = type;
|
||||||
|
|
||||||
|
if (isize > 254) {
|
||||||
|
res[n++] = 0xff;
|
||||||
|
uint16_t size_be = htobe16 (isize);
|
||||||
|
memcpy (res + n, &size_be, sizeof (uint16_t));
|
||||||
|
n += 2;
|
||||||
|
} else {
|
||||||
|
res[n++] = (uint8_t)isize;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (res + n, istream, isize);
|
||||||
|
if (osize)
|
||||||
|
*osize = isize + n;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode TLV from data stream.
|
||||||
|
*/
|
||||||
|
uint8_t *
|
||||||
|
tlv_decode (const uint8_t *istream, uint8_t *type, uint16_t *size)
|
||||||
|
{
|
||||||
|
size_t s;
|
||||||
|
off_t o = 1;
|
||||||
|
uint8_t *res = NULL;
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
*type = istream[0];
|
||||||
|
|
||||||
|
if (istream[1] == 0xff) {
|
||||||
|
uint16_t be_size;
|
||||||
|
memcpy (&be_size, istream + 2, sizeof (uint16_t));
|
||||||
|
s = be16toh(be_size);
|
||||||
|
o += 3;
|
||||||
|
} else {
|
||||||
|
s = istream[1];
|
||||||
|
o += 1;
|
||||||
|
}
|
||||||
|
if (size) {
|
||||||
|
*size = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = malloc (s))) {
|
||||||
|
memcpy (res, istream + o, s);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
|
@ -16,7 +16,8 @@ noinst_LTLIBRARIES = \
|
||||||
test_mifare_classic.la \
|
test_mifare_classic.la \
|
||||||
test_mifare_classic_create_trailer_block.la \
|
test_mifare_classic_create_trailer_block.la \
|
||||||
test_mifare_classic_application.la \
|
test_mifare_classic_application.la \
|
||||||
test_mifare_ultralight.la
|
test_mifare_ultralight.la \
|
||||||
|
test_tlv.la
|
||||||
|
|
||||||
AM_LDFLAGS = -module -rpath $(libdir) -avoid-version -no-undefined
|
AM_LDFLAGS = -module -rpath $(libdir) -avoid-version -no-undefined
|
||||||
|
|
||||||
|
@ -39,6 +40,9 @@ test_mifare_ultralight_la_SOURCES = test_mifare_ultralight.c \
|
||||||
mifare_ultralight_fixture.h
|
mifare_ultralight_fixture.h
|
||||||
test_mifare_ultralight_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
|
test_mifare_ultralight_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
|
||||||
|
|
||||||
|
test_tlv_la_SOURCES = test_tlv.c
|
||||||
|
test_tlv_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
|
||||||
|
|
||||||
echo-cutter:
|
echo-cutter:
|
||||||
@echo $(CUTTER)
|
@echo $(CUTTER)
|
||||||
|
|
||||||
|
|
131
test/test_tlv.c
Normal file
131
test/test_tlv.c
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (C) 2010, Romain Tartiere, Romuald Conty.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cutter.h>
|
||||||
|
|
||||||
|
#include <freefare.h>
|
||||||
|
|
||||||
|
const uint8_t shortdata[] = "elephant"; /* read: "elephant\0" = 9 bytes! */
|
||||||
|
const uint8_t eshortdata[] = "\x03" "\x09" "elephant";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Many thanks to Charles Baudelaire for helping me
|
||||||
|
* test things and helping you realize your f**king
|
||||||
|
* OS / compiler does not support UTF-8 ;-)
|
||||||
|
*/
|
||||||
|
const uint8_t longdata[] = "Dans une terre grasse et pleine d'escargots\n"
|
||||||
|
"Je veux creuser moi-même une fosse profonde,\n"
|
||||||
|
"Où je puisse à loisir étaler mes vieux os\n"
|
||||||
|
"Et dormir dans l'oubli comme un requin dans l'onde.\n"
|
||||||
|
"Je hais les testaments et je hais les tombeaux;\n"
|
||||||
|
"Plutôt que d'implorer une larme du monde,\n"
|
||||||
|
"Vivant, j'aimerais mieux inviter les corbeaux\n"
|
||||||
|
"À saigner tous les bouts de ma carcasse immonde.\n"
|
||||||
|
"Ô vers! noirs compagnons sans oreille et sans yeux,\n"
|
||||||
|
"Voyez venir à vous un mort libre et joyeux;\n"
|
||||||
|
"Philosophes viveurs, fils de la pourriture,\n"
|
||||||
|
"À travers ma ruine allez donc sans remords,\n"
|
||||||
|
"Et dites-moi s'il est encor quelque torture\n"
|
||||||
|
"Pour ce vieux corps sans âme et mort parmi les morts!\n";
|
||||||
|
|
||||||
|
const uint8_t elongdata[] = "\x07" "\xff\x02\x95"
|
||||||
|
"Dans une terre grasse et pleine d'escargots\n"
|
||||||
|
"Je veux creuser moi-même une fosse profonde,\n"
|
||||||
|
"Où je puisse à loisir étaler mes vieux os\n"
|
||||||
|
"Et dormir dans l'oubli comme un requin dans l'onde.\n"
|
||||||
|
"Je hais les testaments et je hais les tombeaux;\n"
|
||||||
|
"Plutôt que d'implorer une larme du monde,\n"
|
||||||
|
"Vivant, j'aimerais mieux inviter les corbeaux\n"
|
||||||
|
"À saigner tous les bouts de ma carcasse immonde.\n"
|
||||||
|
"Ô vers! noirs compagnons sans oreille et sans yeux,\n"
|
||||||
|
"Voyez venir à vous un mort libre et joyeux;\n"
|
||||||
|
"Philosophes viveurs, fils de la pourriture,\n"
|
||||||
|
"À travers ma ruine allez donc sans remords,\n"
|
||||||
|
"Et dites-moi s'il est encor quelque torture\n"
|
||||||
|
"Pour ce vieux corps sans âme et mort parmi les morts!\n";
|
||||||
|
|
||||||
|
void
|
||||||
|
test_tlv_encode_short (void)
|
||||||
|
{
|
||||||
|
uint8_t *res;
|
||||||
|
size_t osize;
|
||||||
|
|
||||||
|
res = tlv_encode (3, shortdata, sizeof (shortdata), &osize);
|
||||||
|
cut_assert_equal_int (11, osize, cut_message ("Wrong encoded message length."));
|
||||||
|
cut_assert_equal_int (3, res[0], cut_message ("Wrong type"));
|
||||||
|
cut_assert_equal_int (9, res[1], cut_message ("Wrong value length"));
|
||||||
|
cut_assert_equal_memory (res, osize, eshortdata, sizeof (eshortdata), cut_message ("Wrong encoded value"));
|
||||||
|
free (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_tlv_encode_long (void)
|
||||||
|
{
|
||||||
|
uint8_t *res;
|
||||||
|
size_t osize;
|
||||||
|
|
||||||
|
res = tlv_encode (7, longdata, sizeof (longdata), &osize);
|
||||||
|
cut_assert_equal_int (665, osize, cut_message ("Wrong encoded message length."));
|
||||||
|
cut_assert_equal_int (7, res[0], cut_message ("Wrong type"));
|
||||||
|
cut_assert_equal_int (0xff, res[1], cut_message ("Wrong value length"));
|
||||||
|
cut_assert_equal_int (0x02, res[2], cut_message ("Wrong value length"));
|
||||||
|
cut_assert_equal_int (0x95, res[3], cut_message ("Wrong value length"));
|
||||||
|
cut_assert_equal_memory (res, osize, elongdata, sizeof (elongdata), cut_message ("Wrong encoded value"));
|
||||||
|
free (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_tlv_decode_short (void)
|
||||||
|
{
|
||||||
|
uint8_t *res;
|
||||||
|
uint16_t size;
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
res = tlv_decode (eshortdata, &type, &size);
|
||||||
|
cut_assert_equal_int (3, type, cut_message ("Wrong type"));
|
||||||
|
cut_assert_equal_int (9, size, cut_message ("Wrong value length"));
|
||||||
|
cut_assert_equal_memory (res, size, shortdata, sizeof (shortdata), cut_message ("Wrong decoded value"));
|
||||||
|
free (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_tlv_decode_long (void)
|
||||||
|
{
|
||||||
|
uint8_t *res;
|
||||||
|
uint16_t size;
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
res = tlv_decode (elongdata, &type, &size);
|
||||||
|
cut_assert_equal_int (7, type, cut_message ("Wrong type"));
|
||||||
|
cut_assert_equal_int (0x295, size, cut_message ("Wrong value length"));
|
||||||
|
cut_assert_equal_memory (res, size, longdata, sizeof (longdata), cut_message ("Wrong decoded value"));
|
||||||
|
free (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_tlv_rfu (void)
|
||||||
|
{
|
||||||
|
uint8_t *data = malloc (0xffff);
|
||||||
|
cut_assert_not_null (data, cut_message ("Out of memory"));
|
||||||
|
|
||||||
|
uint8_t *res = tlv_encode (7, data, 0xffff, NULL);
|
||||||
|
cut_assert_null (res, cut_message ("Size reserved for future use"));
|
||||||
|
|
||||||
|
free (data);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue