mirror of https://gerrit.osmocom.org/libosmocore
gsm0408_test: test encoding and decoding Mobile Identity
One would think by now we would solidly encode and decode Mobile Identities. Well, guess again. - rc is sometimes the amount of bytes written, sometimes actual strlen(). - on string truncation, rc is sometimes strlen() (assuming nul terminated), and sometimes snprintf()-style would-be strlen(). - returned string, when truncated by not enough buffer size, is sometimes nul terminated, sometimes not. - gsm48_mi_to_string() happily reads a byte from zero-length input buffer. - gsm48_mi_to_string() happily writes to zero length output buffer. - gsm48_mi_to_string() returns nonempty string for empty input. - encoding a MI type that still has the GSM_MI_ODD flag set results in encoding an even-length MI as odd-length (hence appending a stray 'F'). I am going to tweak the implementation of gsm48 mobile identity encoding / decoding, so first pinpoint the current behavior in a unit test, and show how perforated even such a seemingly trivial API can be. Change-Id: Iaae3af87f82f1a8f2e6273984c011b2813038cf7
This commit is contained in:
parent
2ca8cebac6
commit
496862818d
|
@ -352,11 +352,246 @@ static void test_mid_from_imsi(void)
|
|||
printf("passed: [%u] %s\n", len, osmo_hexdump(buf, len));
|
||||
}
|
||||
|
||||
struct test_mid_encode_decode_test {
|
||||
uint8_t mi_type;
|
||||
const char *mi_str;
|
||||
size_t str_size;
|
||||
const char *expect_mi_tlv_hex;
|
||||
const char *expect_str;
|
||||
int expect_rc;
|
||||
};
|
||||
|
||||
static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = {
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMSI,
|
||||
.mi_str = "123456789012345",
|
||||
.expect_mi_tlv_hex = "17081932547698103254",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMSI,
|
||||
.mi_str = "12345678901234",
|
||||
.expect_mi_tlv_hex = "170811325476981032f4",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMSI,
|
||||
.mi_str = "423423",
|
||||
.expect_mi_tlv_hex = "1704413224f3",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMSI | GSM_MI_ODD,
|
||||
.mi_str = "423423",
|
||||
.expect_mi_tlv_hex = "1704493224f3", /* encodes "odd" for even number of digits! */
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMSI,
|
||||
.mi_str = "4234235",
|
||||
.expect_mi_tlv_hex = "170449322453",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMSI,
|
||||
.mi_str = "4234235",
|
||||
.expect_mi_tlv_hex = "170449322453",
|
||||
.str_size = 4,
|
||||
.expect_str = "423",
|
||||
.expect_rc = 3, /* exception: on truncation, gsm48_mi_to_string() returns strlen(), not bytes! */
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMEI,
|
||||
.mi_str = "123456789012345",
|
||||
.expect_mi_tlv_hex = "17081a32547698103254",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMEI,
|
||||
.mi_str = "98765432109876",
|
||||
.expect_mi_tlv_hex = "170892785634129078f6",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMEI,
|
||||
.mi_str = "987654321098765",
|
||||
.expect_mi_tlv_hex = "17089a78563412907856",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMEISV,
|
||||
.mi_str = "987654321098765432",
|
||||
.expect_mi_tlv_hex = "170a937856341290785634f2",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_IMEISV,
|
||||
.mi_str = "987654321098765432",
|
||||
.expect_mi_tlv_hex = "170a937856341290785634f2",
|
||||
.str_size = 16,
|
||||
.expect_str = "987654321098765",
|
||||
.expect_rc = 15, /* exception: on truncation, gsm48_mi_to_string() returns strlen(), not bytes! */
|
||||
},
|
||||
{
|
||||
/* gsm48 treats TMSI as decimal string */
|
||||
.mi_type = GSM_MI_TYPE_TMSI,
|
||||
.mi_str = "305419896", /* 0x12345678 as decimal */
|
||||
.expect_mi_tlv_hex = "1705f412345678",
|
||||
.expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_TMSI,
|
||||
.mi_str = "12648430", /* 0xc0ffee as decimal */
|
||||
.expect_mi_tlv_hex = "1705f400c0ffee",
|
||||
.expect_rc = 8, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_TMSI,
|
||||
.mi_str = "0",
|
||||
.expect_mi_tlv_hex = "1705f400000000",
|
||||
.expect_rc = 1, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
|
||||
},
|
||||
{
|
||||
/* gsm48 treats TMSI as decimal string */
|
||||
.mi_type = GSM_MI_TYPE_TMSI,
|
||||
.mi_str = "305419896", /* 0x12345678 as decimal */
|
||||
.expect_mi_tlv_hex = "1705f412345678",
|
||||
.str_size = 5,
|
||||
.expect_str = "3054",
|
||||
.expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns would-be strlen() like snprintf()! */
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_NONE,
|
||||
.mi_str = "123",
|
||||
.expect_mi_tlv_hex = "17021832", /* encoding invalid MI type */
|
||||
.expect_str = "",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_TYPE_NONE,
|
||||
.mi_str = "1234",
|
||||
.expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
|
||||
.expect_str = "",
|
||||
},
|
||||
{
|
||||
.mi_type = GSM_MI_ODD,
|
||||
.mi_str = "1234",
|
||||
.expect_mi_tlv_hex = "17031832f4", /* encoding invalid MI type, and "odd" for an even number of digits */
|
||||
.expect_str = "",
|
||||
},
|
||||
};
|
||||
|
||||
static void test_mid_encode_decode(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("\nTesting Mobile Identity conversions\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(test_mid_encode_decode_tests); i++) {
|
||||
const struct test_mid_encode_decode_test *t = &test_mid_encode_decode_tests[i];
|
||||
uint8_t tlv_buf[64];
|
||||
uint8_t *mi_buf;
|
||||
int tlv_len;
|
||||
int mi_len;
|
||||
const char *tlv_hex;
|
||||
char str[64] = {};
|
||||
size_t str_size = t->str_size ? : sizeof(str);
|
||||
const char *expect_str = t->expect_str ? : t->mi_str;
|
||||
int expect_rc = t->expect_rc ? : strlen(expect_str)+1;
|
||||
int rc;
|
||||
int str_len;
|
||||
|
||||
printf("- %s %s\n", gsm48_mi_type_name(t->mi_type), t->mi_str);
|
||||
if (t->mi_type == GSM_MI_TYPE_TMSI)
|
||||
tlv_len = gsm48_generate_mid_from_tmsi(tlv_buf, (uint32_t)atoll(t->mi_str));
|
||||
else
|
||||
tlv_len = gsm48_generate_mid(tlv_buf, t->mi_str, t->mi_type);
|
||||
tlv_hex = osmo_hexdump_nospc(tlv_buf, tlv_len);
|
||||
|
||||
printf(" -> MI-TLV-hex='%s'\n", tlv_hex);
|
||||
if (t->expect_mi_tlv_hex && strcmp(tlv_hex, t->expect_mi_tlv_hex)) {
|
||||
printf(" ERROR: expected '%s'\n", t->expect_mi_tlv_hex);
|
||||
}
|
||||
|
||||
/* skip the GSM48_IE_MOBILE_ID tag and length */
|
||||
mi_buf = tlv_buf + 2;
|
||||
mi_len = tlv_len - 2;
|
||||
|
||||
rc = gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
|
||||
printf(" -> MI-str=%s rc=%d\n", osmo_quote_str(str, -1), rc);
|
||||
if (strcmp(str, expect_str))
|
||||
printf(" ERROR: expected MI-str=%s\n", osmo_quote_str(expect_str, -1));
|
||||
if (rc != expect_rc)
|
||||
printf(" ERROR: expected rc=%d\n", expect_rc);
|
||||
|
||||
/* Now make sure the resulting string is always '\0' terminated.
|
||||
* The above started out with a zeroed buffer, now repeat with a tainted one. */
|
||||
str_len = strlen(str);
|
||||
str[str_len] = '!';
|
||||
gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
|
||||
if (strlen(str) != str_len)
|
||||
printf(" ERROR: resulting string is not explicitly nul terminated\n");
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t test_mid_decode_zero_length_types[] = { GSM_MI_TYPE_IMSI, GSM_MI_TYPE_TMSI, GSM_MI_TYPE_NONE };
|
||||
|
||||
static void test_mid_decode_zero_length(void)
|
||||
{
|
||||
int odd;
|
||||
uint8_t valid_mi[64];
|
||||
int valid_mi_len;
|
||||
|
||||
printf("\nDecoding zero length Mobile Identities\n");
|
||||
|
||||
/* IMSI = 123456789012345 */
|
||||
valid_mi_len = osmo_hexparse("1932547698103254", valid_mi, sizeof(valid_mi));
|
||||
|
||||
for (odd = 0; odd <= 1; odd++) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(test_mid_decode_zero_length_types); i++) {
|
||||
uint8_t mi_type = test_mid_decode_zero_length_types[i] | (odd ? GSM_MI_ODD : 0);
|
||||
char str[8] = {};
|
||||
int rc;
|
||||
|
||||
printf("- MI type: %s%s\n", gsm48_mi_type_name(mi_type & GSM_MI_TYPE_MASK),
|
||||
odd ? " | GSM_MI_ODD":"");
|
||||
valid_mi[0] = (valid_mi[0] & 0xf0) | mi_type;
|
||||
|
||||
printf(" - writing to zero-length string:\n");
|
||||
memset(str, '!', sizeof(str) - 1);
|
||||
rc = gsm48_mi_to_string(str, 0, valid_mi, valid_mi_len);
|
||||
printf(" rc=%d\n", rc);
|
||||
if (str[0] == '!')
|
||||
printf(" nothing written\n");
|
||||
else
|
||||
printf(" ERROR: Wrote to invalid memory!\n");
|
||||
|
||||
printf(" - writing to 1-byte-length string:\n");
|
||||
memset(str, '!', sizeof(str) - 1);
|
||||
rc = gsm48_mi_to_string(str, 1, valid_mi, valid_mi_len);
|
||||
printf(" rc=%d\n", rc);
|
||||
if (str[0] == '\0')
|
||||
printf(" returned empty string\n");
|
||||
else if (str[0] == '!')
|
||||
printf(" ERROR: nothing written, expected nul-terminated empty string\n");
|
||||
else
|
||||
printf(" ERROR: Wrote unexpected string %s\n", osmo_quote_str(str, 5));
|
||||
if (str[1] != '!')
|
||||
printf(" ERROR: Wrote to invalid memory!\n");
|
||||
|
||||
printf(" - decode zero-length mi:\n");
|
||||
memset(str, '!', sizeof(str) - 1);
|
||||
rc = gsm48_mi_to_string(str, sizeof(str), valid_mi, 0);
|
||||
printf(" rc=%d\n", rc);
|
||||
if (str[0] == '\0')
|
||||
printf(" returned empty string\n");
|
||||
else if (str[0] == '!')
|
||||
printf(" ERROR: nothing written, expected nul-terminated empty string\n");
|
||||
else
|
||||
printf(" ERROR: expected empty string, got output string: %s\n", osmo_quote_str(str, -1));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_bearer_cap();
|
||||
test_mid_from_tmsi();
|
||||
test_mid_from_imsi();
|
||||
test_mid_encode_decode();
|
||||
test_mid_decode_zero_length();
|
||||
test_ra_cap();
|
||||
test_lai_encode_decode();
|
||||
|
||||
|
|
|
@ -2,6 +2,129 @@ Test `CSD 9600/V.110/transparent' passed
|
|||
Test `Speech, all codecs' passed
|
||||
Simple TMSI encoding test....passed
|
||||
Simple IMSI encoding test....passed: [10] 17 08 99 10 07 00 00 00 64 02
|
||||
|
||||
Testing Mobile Identity conversions
|
||||
- IMSI 123456789012345
|
||||
-> MI-TLV-hex='17081932547698103254'
|
||||
-> MI-str="123456789012345" rc=16
|
||||
- IMSI 12345678901234
|
||||
-> MI-TLV-hex='170811325476981032f4'
|
||||
-> MI-str="12345678901234" rc=15
|
||||
- IMSI 423423
|
||||
-> MI-TLV-hex='1704413224f3'
|
||||
-> MI-str="423423" rc=7
|
||||
- unknown 0x9 423423
|
||||
-> MI-TLV-hex='1704493224f3'
|
||||
-> MI-str="423423F" rc=8
|
||||
ERROR: expected MI-str="423423"
|
||||
ERROR: expected rc=7
|
||||
- IMSI 4234235
|
||||
-> MI-TLV-hex='170449322453'
|
||||
-> MI-str="4234235" rc=8
|
||||
- IMSI 4234235
|
||||
-> MI-TLV-hex='170449322453'
|
||||
-> MI-str="423" rc=3
|
||||
ERROR: resulting string is not explicitly nul terminated
|
||||
- IMEI 123456789012345
|
||||
-> MI-TLV-hex='17081a32547698103254'
|
||||
-> MI-str="123456789012345" rc=16
|
||||
- IMEI 98765432109876
|
||||
-> MI-TLV-hex='170892785634129078f6'
|
||||
-> MI-str="98765432109876" rc=15
|
||||
- IMEI 987654321098765
|
||||
-> MI-TLV-hex='17089a78563412907856'
|
||||
-> MI-str="987654321098765" rc=16
|
||||
- IMEI-SV 987654321098765432
|
||||
-> MI-TLV-hex='170a937856341290785634f2'
|
||||
-> MI-str="987654321098765432" rc=19
|
||||
- IMEI-SV 987654321098765432
|
||||
-> MI-TLV-hex='170a937856341290785634f2'
|
||||
-> MI-str="987654321098765" rc=15
|
||||
ERROR: resulting string is not explicitly nul terminated
|
||||
- TMSI 305419896
|
||||
-> MI-TLV-hex='1705f412345678'
|
||||
-> MI-str="305419896" rc=9
|
||||
- TMSI 12648430
|
||||
-> MI-TLV-hex='1705f400c0ffee'
|
||||
-> MI-str="12648430" rc=8
|
||||
- TMSI 0
|
||||
-> MI-TLV-hex='1705f400000000'
|
||||
-> MI-str="0" rc=1
|
||||
- TMSI 305419896
|
||||
-> MI-TLV-hex='1705f412345678'
|
||||
-> MI-str="3054" rc=9
|
||||
- NONE 123
|
||||
-> MI-TLV-hex='17021832'
|
||||
-> MI-str="" rc=1
|
||||
- NONE 1234
|
||||
-> MI-TLV-hex='17031032f4'
|
||||
-> MI-str="" rc=1
|
||||
- unknown 0x8 1234
|
||||
-> MI-TLV-hex='17031832f4'
|
||||
-> MI-str="" rc=1
|
||||
|
||||
Decoding zero length Mobile Identities
|
||||
- MI type: IMSI
|
||||
- writing to zero-length string:
|
||||
rc=1
|
||||
ERROR: Wrote to invalid memory!
|
||||
- writing to 1-byte-length string:
|
||||
rc=1
|
||||
ERROR: Wrote unexpected string "1!!!!"
|
||||
- decode zero-length mi:
|
||||
rc=2
|
||||
ERROR: expected empty string, got output string: "1"
|
||||
- MI type: TMSI
|
||||
- writing to zero-length string:
|
||||
rc=1
|
||||
ERROR: Wrote to invalid memory!
|
||||
- writing to 1-byte-length string:
|
||||
rc=1
|
||||
returned empty string
|
||||
- decode zero-length mi:
|
||||
rc=1
|
||||
returned empty string
|
||||
- MI type: NONE
|
||||
- writing to zero-length string:
|
||||
rc=1
|
||||
ERROR: Wrote to invalid memory!
|
||||
- writing to 1-byte-length string:
|
||||
rc=1
|
||||
returned empty string
|
||||
- decode zero-length mi:
|
||||
rc=1
|
||||
returned empty string
|
||||
- MI type: IMSI | GSM_MI_ODD
|
||||
- writing to zero-length string:
|
||||
rc=1
|
||||
ERROR: Wrote to invalid memory!
|
||||
- writing to 1-byte-length string:
|
||||
rc=1
|
||||
ERROR: Wrote unexpected string "1!!!!"
|
||||
- decode zero-length mi:
|
||||
rc=2
|
||||
ERROR: expected empty string, got output string: "1"
|
||||
- MI type: TMSI | GSM_MI_ODD
|
||||
- writing to zero-length string:
|
||||
rc=1
|
||||
ERROR: Wrote to invalid memory!
|
||||
- writing to 1-byte-length string:
|
||||
rc=1
|
||||
returned empty string
|
||||
- decode zero-length mi:
|
||||
rc=1
|
||||
returned empty string
|
||||
- MI type: NONE | GSM_MI_ODD
|
||||
- writing to zero-length string:
|
||||
rc=1
|
||||
ERROR: Wrote to invalid memory!
|
||||
- writing to 1-byte-length string:
|
||||
rc=1
|
||||
returned empty string
|
||||
- decode zero-length mi:
|
||||
rc=1
|
||||
returned empty string
|
||||
|
||||
Constructed RA:
|
||||
077-121-666-5
|
||||
MCC+MNC in BCD: 70 17 21
|
||||
|
|
Loading…
Reference in New Issue