~noskcaj/ubuntu/saucy/sflphone/merge-1.2.3-2

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjnath/src/pjnath-test/stun.c

  • Committer: Jackson Doak
  • Date: 2013-07-10 21:04:46 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: noskcaj@ubuntu.com-20130710210446-y8f587vza807icr9
Properly merged from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: stun.c 3553 2011-05-05 06:14:19Z nanang $ */
 
2
/*
 
3
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 
4
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 */
 
20
#include "test.h"
 
21
 
 
22
#define THIS_FILE   "stun.c"
 
23
 
 
24
static pj_stun_msg* create1(pj_pool_t*);
 
25
static int verify1(pj_stun_msg*);
 
26
static int verify2(pj_stun_msg*);
 
27
static int verify5(pj_stun_msg*);
 
28
 
 
29
static struct test
 
30
{
 
31
    const char    *title;
 
32
    char              *pdu;
 
33
    unsigned       pdu_len;
 
34
    pj_stun_msg* (*create)(pj_pool_t*);
 
35
    pj_status_t    expected_status;
 
36
    int          (*verify)(pj_stun_msg*);
 
37
} tests[] =
 
38
{
 
39
    {
 
40
        "Invalid message type",
 
41
        "\x11\x01\x00\x00\x21\x12\xa4\x42"
 
42
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
 
43
        20,
 
44
        NULL,
 
45
        PJNATH_EINSTUNMSGTYPE,
 
46
        NULL
 
47
    },
 
48
    {
 
49
        "Short message (1) (partial header)",
 
50
        "\x00\x01",
 
51
        2,
 
52
        NULL,
 
53
        PJNATH_EINSTUNMSGLEN,
 
54
        NULL
 
55
    },
 
56
    {
 
57
        "Short message (2) (partial header)",
 
58
        "\x00\x01\x00\x00\x21\x12\xa4\x42"
 
59
        "\x00\x00\x00\x00\x00\x00\x00\x00",
 
60
        16,
 
61
        NULL,
 
62
        PJNATH_EINSTUNMSGLEN,
 
63
        NULL
 
64
    },
 
65
    {
 
66
        "Short message (3), (missing attribute)",
 
67
        "\x00\x01\x00\x08\x21\x12\xa4\x42"
 
68
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
 
69
        20,
 
70
        NULL,
 
71
        PJNATH_EINSTUNMSGLEN,
 
72
        NULL
 
73
    },
 
74
    {
 
75
        "Short message (4), (partial attribute header)",
 
76
        "\x00\x01\x00\x08\x21\x12\xa4\x42"
 
77
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
78
        "\x80\x28",
 
79
        22,
 
80
        NULL,
 
81
        PJNATH_EINSTUNMSGLEN,
 
82
        NULL
 
83
    },
 
84
    {
 
85
        "Short message (5), (partial attribute header)",
 
86
        "\x00\x01\x00\x08\x21\x12\xa4\x42"
 
87
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
88
        "\x80\x28\x00",
 
89
        23,
 
90
        NULL,
 
91
        PJNATH_EINSTUNMSGLEN,
 
92
        NULL
 
93
    },
 
94
    {
 
95
        "Short message (6), (partial attribute header)",
 
96
        "\x00\x01\x00\x08\x21\x12\xa4\x42"
 
97
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
98
        "\x80\x28\x00\x04",
 
99
        24,
 
100
        NULL,
 
101
        PJNATH_EINSTUNMSGLEN,
 
102
        NULL
 
103
    },
 
104
    {
 
105
        "Short message (7), (partial attribute body)",
 
106
        "\x00\x01\x00\x08\x21\x12\xa4\x42"
 
107
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
108
        "\x80\x28\x00\x04\x00\x00\x00",
 
109
        27,
 
110
        NULL,
 
111
        PJNATH_EINSTUNMSGLEN,
 
112
        NULL
 
113
    },
 
114
    {
 
115
        "Message length in header is too long",
 
116
        "\x00\x01\xff\xff\x21\x12\xa4\x42"
 
117
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
118
        "\x80\x28\x00\x04\x00\x00\x00",
 
119
        27,
 
120
        NULL,
 
121
        PJNATH_EINSTUNMSGLEN,
 
122
        NULL
 
123
    },
 
124
    {
 
125
        "Message length in header is shorter",
 
126
        "\x00\x01\x00\x04\x21\x12\xa4\x42"
 
127
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
128
        "\x80\x28\x00\x04\x00\x00\x00\x00",
 
129
        28,
 
130
        NULL,
 
131
        PJNATH_EINSTUNMSGLEN,
 
132
        NULL
 
133
    },
 
134
    {
 
135
        "Invalid magic",
 
136
        "\x00\x01\x00\x08\x00\x12\xa4\x42"
 
137
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
138
        "\x80\x28\x00\x04\x00\x00\x00\x00",
 
139
        28,
 
140
        NULL,
 
141
        PJ_SUCCESS,
 
142
        NULL
 
143
    },
 
144
    {
 
145
        "Character beyond message",
 
146
        "\x00\x01\x00\x08\x21\x12\xa4\x42"
 
147
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
148
        "\x80\x28\x00\x04\x00\x00\x00\x00\x0a",
 
149
        29,
 
150
        NULL,
 
151
        PJNATH_EINSTUNMSGLEN,
 
152
        NULL
 
153
    },
 
154
    {
 
155
        "Respond unknown mandatory attribute with 420 and "
 
156
        "UNKNOWN-ATTRIBUTES attribute",
 
157
        NULL,
 
158
        0,
 
159
        &create1,
 
160
        0,
 
161
        &verify1
 
162
    },
 
163
    {
 
164
        "Unknown but non-mandatory should be okay",
 
165
        "\x00\x01\x00\x08\x21\x12\xa4\x42"
 
166
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
167
        "\x80\xff\x00\x03\x00\x00\x00\x00",
 
168
        28,
 
169
        NULL,
 
170
        PJ_SUCCESS,
 
171
        &verify2
 
172
    },
 
173
    {
 
174
        "String attr length larger than message",
 
175
        "\x00\x01\x00\x08\x00\x12\xa4\x42"
 
176
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
177
        "\x00\x06\x00\xff\x00\x00\x00\x00",
 
178
        28,
 
179
        NULL,
 
180
        PJNATH_ESTUNINATTRLEN,
 
181
        NULL
 
182
    },
 
183
    {
 
184
        "Attribute other than FINGERPRINT after MESSAGE-INTEGRITY is allowed",
 
185
        "\x00\x01\x00\x20\x21\x12\xa4\x42"
 
186
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
187
        "\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
188
                        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I
 
189
        "\x80\x24\x00\x04\x00\x00\x00\x00",  // REFRESH-INTERVAL
 
190
        52,
 
191
        NULL,
 
192
        PJ_SUCCESS,
 
193
        NULL
 
194
    },
 
195
    {
 
196
        "Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed",
 
197
        "\x00\x01\x00\x28\x21\x12\xa4\x42"
 
198
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
199
        "\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
200
                        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I
 
201
        "\x80\x24\x00\x04\x00\x00\x00\x00"  // REFRESH-INTERVAL
 
202
        "\x80\x28\x00\x04\xc7\xde\xdd\x65", // FINGERPRINT
 
203
        60,
 
204
        NULL,
 
205
        PJ_SUCCESS,
 
206
        &verify5
 
207
    },
 
208
    {
 
209
        "Attribute past FINGERPRINT is not allowed",
 
210
        "\x00\x01\x00\x10\x21\x12\xa4\x42"
 
211
        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
212
        "\x80\x28\x00\x04\x00\x00\x00\x00"
 
213
        "\x80\x24\x00\x04\x00\x00\x00\x00",
 
214
        36,
 
215
        NULL,
 
216
        PJNATH_ESTUNFINGERPOS,
 
217
        NULL
 
218
    }
 
219
};
 
220
 
 
221
static const char *err(pj_status_t status)
 
222
{
 
223
    static char errmsg[PJ_ERR_MSG_SIZE];
 
224
    pj_strerror(status, errmsg, sizeof(errmsg));
 
225
    return errmsg;
 
226
}
 
227
 
 
228
static const pj_str_t USERNAME = {"user", 4};
 
229
static const pj_str_t PASSWORD = {"password", 8};
 
230
 
 
231
static int decode_test(void)
 
232
{
 
233
    unsigned i;
 
234
    pj_pool_t *pool;
 
235
    int rc = 0;
 
236
 
 
237
    pool = pj_pool_create(mem, "decode_test", 1024, 1024, NULL);
 
238
 
 
239
    PJ_LOG(3,(THIS_FILE, "  STUN decode test"));
 
240
 
 
241
    for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) {
 
242
        struct test *t = &tests[i];
 
243
        pj_stun_msg *msg, *msg2;
 
244
        pj_uint8_t buf[1500];
 
245
        pj_str_t key;
 
246
        pj_size_t len;
 
247
        pj_status_t status;
 
248
 
 
249
        PJ_LOG(3,(THIS_FILE, "   %s", t->title));
 
250
 
 
251
        if (t->pdu) {
 
252
            status = pj_stun_msg_decode(pool, (pj_uint8_t*)t->pdu, t->pdu_len,
 
253
                                        PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
 
254
                                        &msg, NULL, NULL);
 
255
 
 
256
            /* Check expected decode result */
 
257
            if (t->expected_status != status) {
 
258
                PJ_LOG(1,(THIS_FILE, "    expecting status %d, got %d",
 
259
                          t->expected_status, status));
 
260
                rc = -10;
 
261
                goto on_return;
 
262
            }
 
263
 
 
264
        } else {
 
265
            msg = t->create(pool);
 
266
            status = PJ_SUCCESS;
 
267
        }
 
268
 
 
269
        if (status != PJ_SUCCESS)
 
270
            continue;
 
271
 
 
272
        /* Try to encode message */
 
273
        pj_stun_create_key(pool, &key, NULL, &USERNAME, PJ_STUN_PASSWD_PLAIN, &PASSWORD);
 
274
        status = pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
 
275
        if (status != PJ_SUCCESS) {
 
276
            PJ_LOG(1,(THIS_FILE, "    encode error: %s", err(status)));
 
277
            rc = -40;
 
278
            goto on_return;
 
279
        }
 
280
 
 
281
        /* Try to decode it once more */
 
282
        status = pj_stun_msg_decode(pool, buf, len,
 
283
                                    PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
 
284
                                    &msg2, NULL, NULL);
 
285
        if (status != PJ_SUCCESS) {
 
286
            PJ_LOG(1,(THIS_FILE, "    subsequent decoding failed: %s", err(status)));
 
287
            rc = -50;
 
288
            goto on_return;
 
289
        }
 
290
 
 
291
        /* Verify */
 
292
        if (t->verify) {
 
293
            rc = t->verify(msg);
 
294
            if (rc != 0) {
 
295
                goto on_return;
 
296
            }
 
297
        }
 
298
    }
 
299
 
 
300
on_return:
 
301
    pj_pool_release(pool);
 
302
    if (rc == 0)
 
303
        PJ_LOG(3,(THIS_FILE, "...success!"));
 
304
    return rc;
 
305
}
 
306
 
 
307
/* Create 420 response */
 
308
static pj_stun_msg* create1(pj_pool_t *pool)
 
309
{
 
310
    char *pdu = "\x00\x01\x00\x08\x21\x12\xa4\x42"
 
311
                "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
312
                "\x00\xff\x00\x04\x00\x00\x00\x00";
 
313
    unsigned pdu_len = 28;
 
314
    pj_stun_msg *msg, *res;
 
315
    pj_status_t status;
 
316
 
 
317
    status = pj_stun_msg_decode(pool, (pj_uint8_t*)pdu, pdu_len,
 
318
                                PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
 
319
                                &msg, NULL, &res);
 
320
    pj_assert(status != PJ_SUCCESS);
 
321
    pj_assert(res != NULL);
 
322
 
 
323
    return res;
 
324
}
 
325
 
 
326
/* Error response MUST have ERROR-CODE attribute */
 
327
/* 420 response MUST contain UNKNOWN-ATTRIBUTES */
 
328
static int verify1(pj_stun_msg *msg)
 
329
{
 
330
    pj_stun_errcode_attr *aerr;
 
331
    pj_stun_unknown_attr *aunk;
 
332
 
 
333
    if (!PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) {
 
334
        PJ_LOG(1,(THIS_FILE, "    expecting error message"));
 
335
        return -100;
 
336
    }
 
337
 
 
338
    aerr = (pj_stun_errcode_attr*)
 
339
           pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0);
 
340
    if (aerr == NULL) {
 
341
        PJ_LOG(1,(THIS_FILE, "    missing ERROR-CODE attribute"));
 
342
        return -110;
 
343
    }
 
344
 
 
345
    if (aerr->err_code != 420) {
 
346
        PJ_LOG(1,(THIS_FILE, "    expecting 420 error"));
 
347
        return -120;
 
348
    }
 
349
 
 
350
    aunk = (pj_stun_unknown_attr*)
 
351
           pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, 0);
 
352
    if (aunk == NULL) {
 
353
        PJ_LOG(1,(THIS_FILE, "    missing UNKNOWN-ATTRIBUTE attribute"));
 
354
        return -130;
 
355
    }
 
356
 
 
357
    if (aunk->attr_count != 1) {
 
358
        PJ_LOG(1,(THIS_FILE, "    expecting one unknown attribute"));
 
359
        return -140;
 
360
    }
 
361
 
 
362
    if (aunk->attrs[0] != 0xff) {
 
363
        PJ_LOG(1,(THIS_FILE, "    expecting 0xff as unknown attribute"));
 
364
        return -150;
 
365
    }
 
366
 
 
367
    return 0;
 
368
}
 
369
 
 
370
/* Attribute count should be zero since unknown attribute is not parsed */
 
371
static int verify2(pj_stun_msg *msg)
 
372
{
 
373
    pj_stun_binary_attr *bin_attr;
 
374
 
 
375
    if (msg->attr_count != 1) {
 
376
        PJ_LOG(1,(THIS_FILE, "    expecting one attribute count"));
 
377
        return -200;
 
378
    }
 
379
 
 
380
    bin_attr = (pj_stun_binary_attr*)msg->attr[0];
 
381
    if (bin_attr->hdr.type != 0x80ff) {
 
382
        PJ_LOG(1,(THIS_FILE, "    expecting attribute type 0x80ff"));
 
383
        return -210;
 
384
    }
 
385
    if (bin_attr->hdr.length != 3) {
 
386
        PJ_LOG(1,(THIS_FILE, "    expecting attribute length = 4"));
 
387
        return -220;
 
388
    }
 
389
    if (bin_attr->magic != PJ_STUN_MAGIC) {
 
390
        PJ_LOG(1,(THIS_FILE, "    expecting PJ_STUN_MAGIC for unknown attr"));
 
391
        return -230;
 
392
    }
 
393
    if (bin_attr->length != 3) {
 
394
        PJ_LOG(1,(THIS_FILE, "    expecting data length 4"));
 
395
        return -240;
 
396
    }
 
397
 
 
398
    return 0;
 
399
}
 
400
 
 
401
 
 
402
/* Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed */
 
403
static int verify5(pj_stun_msg *msg)
 
404
{
 
405
    if (msg->attr_count != 3) {
 
406
        PJ_LOG(1,(THIS_FILE, "    expecting 3 attribute count"));
 
407
        return -500;
 
408
    }
 
409
 
 
410
    if (msg->attr[0]->type != PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
 
411
        PJ_LOG(1,(THIS_FILE, "    expecting MESSAGE-INTEGRITY"));
 
412
        return -510;
 
413
    }
 
414
    if (msg->attr[1]->type != PJ_STUN_ATTR_REFRESH_INTERVAL) {
 
415
        PJ_LOG(1,(THIS_FILE, "    expecting REFRESH-INTERVAL"));
 
416
        return -520;
 
417
    }
 
418
    if (msg->attr[2]->type != PJ_STUN_ATTR_FINGERPRINT) {
 
419
        PJ_LOG(1,(THIS_FILE, "    expecting FINGERPRINT"));
 
420
        return -530;
 
421
    }
 
422
 
 
423
    return 0;
 
424
}
 
425
 
 
426
 
 
427
static int decode_verify(void)
 
428
{
 
429
    /* Decode all attribute types */
 
430
    return 0;
 
431
}
 
432
 
 
433
/*
 
434
 * Test vectors, from:
 
435
 * http://tools.ietf.org/html/draft-denis-behave-rfc3489bis-test-vectors-02
 
436
 */
 
437
typedef struct test_vector test_vector;
 
438
 
 
439
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v);
 
440
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v);
 
441
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v);
 
442
 
 
443
enum
 
444
{
 
445
    USE_MESSAGE_INTEGRITY   = 1,
 
446
    USE_FINGERPRINT         = 2
 
447
};
 
448
 
 
449
static struct test_vector
 
450
{
 
451
    unsigned       msg_type;
 
452
    char          *tsx_id;
 
453
    char          *pdu;
 
454
    unsigned       pdu_len;
 
455
    unsigned       options;
 
456
    char          *username;
 
457
    char          *password;
 
458
    char          *realm;
 
459
    char          *nonce;
 
460
    pj_stun_msg* (*create)(pj_pool_t*, test_vector*);
 
461
} test_vectors[] =
 
462
{
 
463
    {
 
464
        PJ_STUN_BINDING_REQUEST,
 
465
        "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
 
466
        "\x00\x01\x00\x44\x21\x12\xa4\x42\xb7\xe7"
 
467
        "\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
 
468
        "\x00\x24\x00\x04\x6e\x00\x01\xff\x80\x29"
 
469
        "\x00\x08\x93\x2f\xf9\xb1\x51\x26\x3b\x36"
 
470
        "\x00\x06\x00\x09\x65\x76\x74\x6a\x3a\x68"
 
471
        "\x36\x76\x59\x20\x20\x20\x00\x08\x00\x14"
 
472
        "\x62\x4e\xeb\xdc\x3c\xc9\x2d\xd8\x4b\x74"
 
473
        "\xbf\x85\xd1\xc0\xf5\xde\x36\x87\xbd\x33"
 
474
        "\x80\x28\x00\x04\xad\x8a\x85\xff",
 
475
        88,
 
476
        USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
 
477
        "evtj:h6vY",
 
478
        "VOkJxbRl1RmTxUk/WvJxBt",
 
479
        "",
 
480
        "",
 
481
        &create_msgint1
 
482
    }
 
483
    /* disabled: see http://trac.pjsip.org/repos/ticket/960
 
484
    ,
 
485
    {
 
486
        PJ_STUN_BINDING_RESPONSE,
 
487
        "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
 
488
        "\x01\x01\x00\x3c"
 
489
        "\x21\x12\xa4\x42"
 
490
        "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae"
 
491
        "\x80\x22\x00\x0b"
 
492
        "\x74\x65\x73\x74\x20\x76\x65\x63\x74\x6f\x72\x20"
 
493
        "\x00\x20\x00\x08"
 
494
        "\x00\x01\xa1\x47\xe1\x12\xa6\x43"
 
495
        "\x00\x08\x00\x14"
 
496
        "\x2b\x91\xf5\x99\xfd\x9e\x90\xc3\x8c\x74\x89\xf9"
 
497
        "\x2a\xf9\xba\x53\xf0\x6b\xe7\xd7"
 
498
        "\x80\x28\x00\x04"
 
499
        "\xc0\x7d\x4c\x96",
 
500
        80,
 
501
        USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
 
502
        "evtj:h6vY",
 
503
        "VOkJxbRl1RmTxUk/WvJxBt",
 
504
        "",
 
505
        "",
 
506
        &create_msgint2
 
507
    }
 
508
    */
 
509
 
 
510
    /* disabled: see http://trac.pjsip.org/repos/ticket/960
 
511
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
 
512
    ,
 
513
    {
 
514
        PJ_STUN_BINDING_RESPONSE,
 
515
        "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae",
 
516
        "\x01\x01\x00\x48" //     Response type and message length
 
517
        "\x21\x12\xa4\x42" //     Message cookie
 
518
        "\xb7\xe7\xa7\x01" //  }
 
519
        "\xbc\x34\xd6\x86" //  }  Transaction ID
 
520
        "\xfa\x87\xdf\xae" //  }
 
521
 
 
522
        "\x80\x22\x00\x0b" // SOFTWARE, length=11
 
523
        "\x74\x65\x73\x74"
 
524
        "\x20\x76\x65\x63"
 
525
        "\x74\x6f\x72\x20"
 
526
        "\x00\x20\x00\x14" // XOR-MAPPED-ADDRESS
 
527
        "\x00\x02\xa1\x47"
 
528
        "\x01\x13\xa9\xfa"
 
529
        "\xa5\xd3\xf1\x79"
 
530
        "\xbc\x25\xf4\xb5"
 
531
        "\xbe\xd2\xb9\xd9"
 
532
        "\x00\x08\x00\x14" // MESSAGE-INTEGRITY attribute header
 
533
        "\xa3\x82\x95\x4e" // }
 
534
        "\x4b\xe6\x7b\xf1" // }
 
535
        "\x17\x84\xc9\x7c" // }  HMAC-SHA1 fingerprint
 
536
        "\x82\x92\xc2\x75" // }
 
537
        "\xbf\xe3\xed\x41" // }
 
538
        "\x80\x28\x00\x04" //    FINGERPRINT attribute header
 
539
        "\xc8\xfb\x0b\x4c" //    CRC32 fingerprint
 
540
        ,
 
541
        92,
 
542
        USE_MESSAGE_INTEGRITY | USE_FINGERPRINT,
 
543
        "evtj:h6vY",
 
544
        "VOkJxbRl1RmTxUk/WvJxBt",
 
545
        "",
 
546
        "",
 
547
        &create_msgint3
 
548
    }
 
549
#endif
 
550
    */
 
551
};
 
552
 
 
553
 
 
554
static char* print_binary(const pj_uint8_t *data, unsigned data_len)
 
555
{
 
556
    static char buf[1500];
 
557
    unsigned length = sizeof(buf);
 
558
    char *p = buf;
 
559
    unsigned i;
 
560
 
 
561
    for (i=0; i<data_len;) {
 
562
        unsigned j;
 
563
 
 
564
        pj_ansi_snprintf(p, 1500-(p-buf),
 
565
                         "%04d-%04d   ",
 
566
                         i, (i+20 < data_len) ? i+20 : data_len);
 
567
        p += 12;
 
568
 
 
569
        for (j=0; j<20 && i<data_len && p<(buf+length-10); ++j, ++i) {
 
570
            pj_ansi_sprintf(p, "%02x ", (*data) & 0xFF);
 
571
            p += 3;
 
572
            data++;
 
573
        }
 
574
 
 
575
        pj_ansi_sprintf(p, "\n");
 
576
        p++;
 
577
    }
 
578
 
 
579
    return buf;
 
580
}
 
581
 
 
582
static int cmp_buf(const pj_uint8_t *s1, const pj_uint8_t *s2, unsigned len)
 
583
{
 
584
    unsigned i;
 
585
    for (i=0; i<len; ++i) {
 
586
        if (s1[i] != s2[i])
 
587
            return i;
 
588
    }
 
589
 
 
590
    return -1;
 
591
}
 
592
 
 
593
static int fingerprint_test_vector()
 
594
{
 
595
    pj_pool_t *pool;
 
596
    pj_status_t status;
 
597
    unsigned i;
 
598
    int rc = 0;
 
599
 
 
600
    /* To avoid function not referenced warnings */
 
601
    (void)create_msgint2;
 
602
    (void)create_msgint3;
 
603
 
 
604
    PJ_LOG(3,(THIS_FILE, "  draft-denis-behave-rfc3489bis-test-vectors-02"));
 
605
 
 
606
    pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL);
 
607
 
 
608
    for (i=0; i<PJ_ARRAY_SIZE(test_vectors); ++i) {
 
609
        struct test_vector *v;
 
610
        pj_stun_msg *ref_msg, *msg;
 
611
        pj_size_t parsed_len;
 
612
        pj_size_t len;
 
613
        unsigned pos;
 
614
        pj_uint8_t buf[1500];
 
615
        char print[1500];
 
616
        pj_str_t key;
 
617
 
 
618
        PJ_LOG(3,(THIS_FILE, "    Running test %d/%d", i,
 
619
                  PJ_ARRAY_SIZE(test_vectors)));
 
620
 
 
621
        v = &test_vectors[i];
 
622
 
 
623
        /* Print reference message */
 
624
        PJ_LOG(4,(THIS_FILE, "Reference message PDU:\n%s",
 
625
                  print_binary((pj_uint8_t*)v->pdu, v->pdu_len)));
 
626
 
 
627
        /* Try to parse the reference message first */
 
628
        status = pj_stun_msg_decode(pool, (pj_uint8_t*)v->pdu, v->pdu_len,
 
629
                                    PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
 
630
                                    &ref_msg, &parsed_len, NULL);
 
631
        if (status != PJ_SUCCESS) {
 
632
            PJ_LOG(1,(THIS_FILE, "    Error decoding reference message"));
 
633
            rc = -1010;
 
634
            goto on_return;
 
635
        }
 
636
 
 
637
        if (parsed_len != v->pdu_len) {
 
638
            PJ_LOG(1,(THIS_FILE, "    Parsed len error"));
 
639
            rc = -1020;
 
640
            goto on_return;
 
641
        }
 
642
 
 
643
        /* Print the reference message */
 
644
        pj_stun_msg_dump(ref_msg, print, sizeof(print), NULL);
 
645
        PJ_LOG(4,(THIS_FILE, "Reference message:\n%s", print));
 
646
 
 
647
        /* Create our message */
 
648
        msg = v->create(pool, v);
 
649
        if (msg == NULL) {
 
650
            PJ_LOG(1,(THIS_FILE, "    Error creating stun message"));
 
651
            rc = -1030;
 
652
            goto on_return;
 
653
        }
 
654
 
 
655
        /* Encode message */
 
656
        if (v->options & USE_MESSAGE_INTEGRITY) {
 
657
            pj_str_t s1, s2, r;
 
658
 
 
659
            pj_stun_create_key(pool, &key, pj_cstr(&r, v->realm),
 
660
                               pj_cstr(&s1, v->username),
 
661
                               PJ_STUN_PASSWD_PLAIN,
 
662
                               pj_cstr(&s2, v->password));
 
663
            pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len);
 
664
 
 
665
        } else {
 
666
            pj_stun_msg_encode(msg, buf, sizeof(buf), 0, NULL, &len);
 
667
        }
 
668
 
 
669
        /* Print our raw message */
 
670
        PJ_LOG(4,(THIS_FILE, "Message PDU:\n%s",
 
671
                  print_binary((pj_uint8_t*)buf, len)));
 
672
 
 
673
        /* Print our message */
 
674
        pj_stun_msg_dump(msg, print, sizeof(print), NULL);
 
675
        PJ_LOG(4,(THIS_FILE, "Message is:\n%s", print));
 
676
 
 
677
        /* Compare message length */
 
678
        if (len != v->pdu_len) {
 
679
            PJ_LOG(1,(THIS_FILE, "    Message length mismatch"));
 
680
            rc = -1050;
 
681
            goto on_return;
 
682
        }
 
683
 
 
684
        pos = cmp_buf(buf, (const pj_uint8_t*)v->pdu, len);
 
685
        if (pos != (unsigned)-1) {
 
686
            PJ_LOG(1,(THIS_FILE, "    Message mismatch at byte %d", pos));
 
687
            rc = -1060;
 
688
            goto on_return;
 
689
        }
 
690
 
 
691
        /* Authenticate the request/response */
 
692
        if (v->options & USE_MESSAGE_INTEGRITY) {
 
693
            if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
 
694
                pj_stun_auth_cred cred;
 
695
                pj_status_t status;
 
696
 
 
697
                pj_bzero(&cred, sizeof(cred));
 
698
                cred.type = PJ_STUN_AUTH_CRED_STATIC;
 
699
                cred.data.static_cred.realm = pj_str(v->realm);
 
700
                cred.data.static_cred.username = pj_str(v->username);
 
701
                cred.data.static_cred.data = pj_str(v->password);
 
702
                cred.data.static_cred.nonce = pj_str(v->nonce);
 
703
 
 
704
                status = pj_stun_authenticate_request(buf, len, msg,
 
705
                                                      &cred, pool, NULL, NULL);
 
706
                if (status != PJ_SUCCESS) {
 
707
                    char errmsg[PJ_ERR_MSG_SIZE];
 
708
                    pj_strerror(status, errmsg, sizeof(errmsg));
 
709
                    PJ_LOG(1,(THIS_FILE,
 
710
                              "    Request authentication failed: %s",
 
711
                              errmsg));
 
712
                    rc = -1070;
 
713
                    goto on_return;
 
714
                }
 
715
 
 
716
            } else if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) {
 
717
                pj_status_t status;
 
718
                status = pj_stun_authenticate_response(buf, len, msg, &key);
 
719
                if (status != PJ_SUCCESS) {
 
720
                    char errmsg[PJ_ERR_MSG_SIZE];
 
721
                    pj_strerror(status, errmsg, sizeof(errmsg));
 
722
                    PJ_LOG(1,(THIS_FILE,
 
723
                              "    Response authentication failed: %s",
 
724
                              errmsg));
 
725
                    rc = -1080;
 
726
                    goto on_return;
 
727
                }
 
728
            }
 
729
        }
 
730
    }
 
731
 
 
732
 
 
733
on_return:
 
734
    pj_pool_release(pool);
 
735
    return rc;
 
736
}
 
737
 
 
738
static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v)
 
739
{
 
740
    pj_stun_msg *msg;
 
741
    pj_timestamp u64;
 
742
    pj_str_t s1;
 
743
    pj_status_t status;
 
744
 
 
745
    status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
 
746
                                (pj_uint8_t*)v->tsx_id, &msg);
 
747
    if (status != PJ_SUCCESS)
 
748
        goto on_error;
 
749
 
 
750
    status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY,
 
751
                                       0x6e0001ff);
 
752
    if (status != PJ_SUCCESS)
 
753
        goto on_error;
 
754
 
 
755
    u64.u32.hi = 0x932ff9b1;
 
756
    u64.u32.lo = 0x51263b36;
 
757
    status = pj_stun_msg_add_uint64_attr(pool, msg,
 
758
                                         PJ_STUN_ATTR_ICE_CONTROLLED, &u64);
 
759
    if (status != PJ_SUCCESS)
 
760
        goto on_error;
 
761
 
 
762
    status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME,
 
763
                                         pj_cstr(&s1, v->username));
 
764
    if (status != PJ_SUCCESS)
 
765
        goto on_error;
 
766
 
 
767
    status = pj_stun_msg_add_msgint_attr(pool, msg);
 
768
    if (status != PJ_SUCCESS)
 
769
        goto on_error;
 
770
 
 
771
    status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
 
772
    if (status != PJ_SUCCESS)
 
773
        goto on_error;
 
774
 
 
775
    return msg;
 
776
 
 
777
on_error:
 
778
    app_perror("    error: create_msgint1()", status);
 
779
    return NULL;
 
780
}
 
781
 
 
782
static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v)
 
783
{
 
784
    pj_stun_msg *msg;
 
785
    pj_sockaddr_in mapped_addr;
 
786
    pj_str_t s1;
 
787
    pj_status_t status;
 
788
 
 
789
    status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
 
790
                                (pj_uint8_t*)v->tsx_id, &msg);
 
791
    if (status != PJ_SUCCESS)
 
792
        goto on_error;
 
793
 
 
794
    status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
 
795
                                         pj_cstr(&s1, "test vector"));
 
796
    if (status != PJ_SUCCESS)
 
797
        goto on_error;
 
798
 
 
799
    status = pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "192.0.2.1"),
 
800
                                 32853);
 
801
    if (status != PJ_SUCCESS)
 
802
        goto on_error;
 
803
 
 
804
    status = pj_stun_msg_add_sockaddr_attr(pool, msg,
 
805
                                           PJ_STUN_ATTR_XOR_MAPPED_ADDR,
 
806
                                           PJ_TRUE, &mapped_addr,
 
807
                                           sizeof(pj_sockaddr_in));
 
808
    if (status != PJ_SUCCESS)
 
809
        goto on_error;
 
810
 
 
811
    status = pj_stun_msg_add_msgint_attr(pool, msg);
 
812
    if (status != PJ_SUCCESS)
 
813
        goto on_error;
 
814
 
 
815
    status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
 
816
    if (status != PJ_SUCCESS)
 
817
        goto on_error;
 
818
 
 
819
    return msg;
 
820
 
 
821
on_error:
 
822
    app_perror("    error: create_msgint2()", status);
 
823
    return NULL;
 
824
}
 
825
 
 
826
 
 
827
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v)
 
828
{
 
829
    pj_stun_msg *msg;
 
830
    pj_sockaddr mapped_addr;
 
831
    pj_str_t s1;
 
832
    pj_status_t status;
 
833
 
 
834
    status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
 
835
                                (pj_uint8_t*)v->tsx_id, &msg);
 
836
    if (status != PJ_SUCCESS)
 
837
        goto on_error;
 
838
 
 
839
    status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE,
 
840
                                         pj_cstr(&s1, "test vector"));
 
841
    if (status != PJ_SUCCESS)
 
842
        goto on_error;
 
843
 
 
844
    status = pj_sockaddr_init(pj_AF_INET6(), &mapped_addr,
 
845
                      pj_cstr(&s1, "2001:db8:1234:5678:11:2233:4455:6677"),
 
846
                      32853);
 
847
    if (status != PJ_SUCCESS)
 
848
        goto on_error;
 
849
 
 
850
    status = pj_stun_msg_add_sockaddr_attr(pool, msg,
 
851
                                           PJ_STUN_ATTR_XOR_MAPPED_ADDR,
 
852
                                           PJ_TRUE, &mapped_addr,
 
853
                                           sizeof(pj_sockaddr));
 
854
    if (status != PJ_SUCCESS)
 
855
        goto on_error;
 
856
 
 
857
    status = pj_stun_msg_add_msgint_attr(pool, msg);
 
858
    if (status != PJ_SUCCESS)
 
859
        goto on_error;
 
860
 
 
861
    status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
 
862
    if (status != PJ_SUCCESS)
 
863
        goto on_error;
 
864
 
 
865
    return msg;
 
866
 
 
867
on_error:
 
868
    app_perror("    error: create_msgint3()", status);
 
869
    return NULL;
 
870
}
 
871
 
 
872
 
 
873
/* Compare two messages */
 
874
static int cmp_msg(const pj_stun_msg *msg1, const pj_stun_msg *msg2)
 
875
{
 
876
    unsigned i;
 
877
 
 
878
    if (msg1->hdr.type != msg2->hdr.type)
 
879
        return -10;
 
880
    if (msg1->hdr.length != msg2->hdr.length)
 
881
        return -20;
 
882
    if (msg1->hdr.magic != msg2->hdr.magic)
 
883
        return -30;
 
884
    if (pj_memcmp(msg1->hdr.tsx_id, msg2->hdr.tsx_id, sizeof(msg1->hdr.tsx_id)))
 
885
        return -40;
 
886
    if (msg1->attr_count != msg2->attr_count)
 
887
        return -50;
 
888
 
 
889
    for (i=0; i<msg1->attr_count; ++i) {
 
890
        const pj_stun_attr_hdr *a1 = msg1->attr[i];
 
891
        const pj_stun_attr_hdr *a2 = msg2->attr[i];
 
892
 
 
893
        if (a1->type != a2->type)
 
894
            return -60;
 
895
        if (a1->length != a2->length)
 
896
            return -70;
 
897
    }
 
898
 
 
899
    return 0;
 
900
}
 
901
 
 
902
/* Decode and authenticate message with unknown non-mandatory attribute */
 
903
static int handle_unknown_non_mandatory(void)
 
904
{
 
905
    pj_pool_t *pool = pj_pool_create(mem, NULL, 1000, 1000, NULL);
 
906
    pj_stun_msg *msg0, *msg1, *msg2;
 
907
    pj_uint8_t data[] = { 1, 2, 3, 4, 5, 6};
 
908
    pj_uint8_t packet[500];
 
909
    pj_stun_auth_cred cred;
 
910
    pj_size_t len;
 
911
    pj_status_t rc;
 
912
 
 
913
    PJ_LOG(3,(THIS_FILE, "  handling unknown non-mandatory attr"));
 
914
 
 
915
    PJ_LOG(3,(THIS_FILE, "    encoding"));
 
916
    rc = pj_stun_msg_create(pool, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &msg0);
 
917
    rc += pj_stun_msg_add_string_attr(pool, msg0, PJ_STUN_ATTR_USERNAME, &USERNAME);
 
918
    rc += pj_stun_msg_add_binary_attr(pool, msg0, 0x80ff, data, sizeof(data));
 
919
    rc += pj_stun_msg_add_msgint_attr(pool, msg0);
 
920
    rc += pj_stun_msg_encode(msg0, packet, sizeof(packet), 0, &PASSWORD, &len);
 
921
 
 
922
#if 0
 
923
    if (1) {
 
924
        unsigned i;
 
925
        puts("");
 
926
        printf("{ ");
 
927
        for (i=0; i<len; ++i) printf("0x%02x, ", packet[i]);
 
928
        puts(" }");
 
929
    }
 
930
#endif
 
931
 
 
932
    PJ_LOG(3,(THIS_FILE, "    decoding"));
 
933
    rc += pj_stun_msg_decode(pool, packet, len, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
 
934
                             &msg1, NULL, NULL);
 
935
 
 
936
    rc += cmp_msg(msg0, msg1);
 
937
 
 
938
    pj_bzero(&cred, sizeof(cred));
 
939
    cred.type = PJ_STUN_AUTH_CRED_STATIC;
 
940
    cred.data.static_cred.username = USERNAME;
 
941
    cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
 
942
    cred.data.static_cred.data = PASSWORD;
 
943
 
 
944
    PJ_LOG(3,(THIS_FILE, "    authenticating"));
 
945
    rc += pj_stun_authenticate_request(packet, len, msg1, &cred, pool, NULL, NULL);
 
946
 
 
947
    PJ_LOG(3,(THIS_FILE, "    clone"));
 
948
    msg2 = pj_stun_msg_clone(pool, msg1);
 
949
    rc += cmp_msg(msg0, msg2);
 
950
 
 
951
    pj_pool_release(pool);
 
952
 
 
953
    return rc==0 ? 0 : -4410;
 
954
}
 
955
 
 
956
 
 
957
int stun_test(void)
 
958
{
 
959
    int pad, rc;
 
960
 
 
961
    pad = pj_stun_set_padding_char(32);
 
962
 
 
963
    rc = decode_test();
 
964
    if (rc != 0)
 
965
        goto on_return;
 
966
 
 
967
    rc = decode_verify();
 
968
    if (rc != 0)
 
969
        goto on_return;
 
970
 
 
971
    rc = fingerprint_test_vector();
 
972
    if (rc != 0)
 
973
        goto on_return;
 
974
 
 
975
    rc = handle_unknown_non_mandatory();
 
976
    if (rc != 0)
 
977
        goto on_return;
 
978
 
 
979
on_return:
 
980
    pj_stun_set_padding_char(pad);
 
981
    return rc;
 
982
}