~ubuntu-branches/ubuntu/raring/sflphone/raring

« back to all changes in this revision

Viewing changes to sflphone-common/libs/pjproject/pjnath/src/pjnath-test/stun.c

  • Committer: Package Import Robot
  • Author(s): Francois Marier
  • Date: 2011-11-25 13:24:12 UTC
  • mfrom: (4.1.10 sid)
  • Revision ID: package-import@ubuntu.com-20111125132412-dc4qvhyosk74cd42
Tags: 1.0.1-4
Don't assume that arch:all packages will get built (closes: #649726)

Show diffs side-by-side

added added

removed removed

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