- Timestamp:
- Sep 18, 2007 7:33:33 PM (17 years ago)
- Location:
- pjproject/trunk/pjnath
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/include/pjnath/config.h
r1275 r1439 50 50 51 51 /* ************************************************************************** 52 * STUN C LIENT CONFIGURATION52 * STUN CONFIGURATION 53 53 */ 54 54 … … 81 81 * after this time, the STUN transaction will be considered to have failed. 82 82 * 83 * The default value is 16 00 miliseconds(as per RFC 3489-bis).83 * The default value is 16x RTO (as per RFC 3489-bis). 84 84 */ 85 85 #ifndef PJ_STUN_TIMEOUT_VALUE 86 # define PJ_STUN_TIMEOUT_VALUE 160086 # define PJ_STUN_TIMEOUT_VALUE (16 * PJ_STUN_RTO_VALUE) 87 87 #endif 88 88 … … 121 121 #define PJ_STUN_PORT 3478 122 122 123 124 /** 125 * Padding character for string attributes. 126 * 127 * Default: ASCII 0 128 */ 129 #ifndef PJ_STUN_STRING_ATTR_PAD_CHR 130 # define PJ_STUN_STRING_ATTR_PAD_CHR 0 131 #endif 123 132 124 133 -
pjproject/trunk/pjnath/include/pjnath/stun_msg.h
r1417 r1439 281 281 PJ_STUN_ATTR_CHANGED_ADDR = 0x0005,/**< CHANGED-ADDRESS (deprecatd)*/ 282 282 PJ_STUN_ATTR_USERNAME = 0x0006,/**< USERNAME attribute. */ 283 PJ_STUN_ATTR_PASSWORD = 0x0007,/**< PASSWORD attribute.*/283 PJ_STUN_ATTR_PASSWORD = 0x0007,/**< was PASSWORD attribute. */ 284 284 PJ_STUN_ATTR_MESSAGE_INTEGRITY = 0x0008,/**< MESSAGE-INTEGRITY. */ 285 285 PJ_STUN_ATTR_ERROR_CODE = 0x0009,/**< ERROR-CODE. */ … … 330 330 PJ_STUN_SC_UNAUTHORIZED = 401, /**< Unauthorized */ 331 331 PJ_STUN_SC_UNKNOWN_ATTRIBUTE = 420, /**< Unknown Attribute */ 332 PJ_STUN_SC_STALE_CREDENTIALS = 430, /**< Stale Credentials */ 333 PJ_STUN_SC_INTEGRITY_CHECK_FAILURE = 431, /**< Integrity Chk Fail */ 334 PJ_STUN_SC_MISSING_USERNAME = 432, /**< Missing Username */ 335 PJ_STUN_SC_USE_TLS = 433, /**< Use TLS */ 336 PJ_STUN_SC_MISSING_REALM = 434, /**< Missing Realm */ 337 PJ_STUN_SC_MISSING_NONCE = 435, /**< Missing Nonce */ 338 PJ_STUN_SC_UNKNOWN_USERNAME = 436, /**< Unknown Username */ 339 PJ_STUN_SC_NO_BINDING = 437, /**< No Binding. */ 332 #if 0 333 /* These were obsolete in recent rfc3489bis */ 334 //PJ_STUN_SC_STALE_CREDENTIALS = 430, /**< Stale Credentials */ 335 //PJ_STUN_SC_INTEGRITY_CHECK_FAILURE= 431, /**< Integrity Chk Fail */ 336 //PJ_STUN_SC_MISSING_USERNAME = 432, /**< Missing Username */ 337 //PJ_STUN_SC_USE_TLS = 433, /**< Use TLS */ 338 //PJ_STUN_SC_MISSING_REALM = 434, /**< Missing Realm */ 339 //PJ_STUN_SC_MISSING_NONCE = 435, /**< Missing Nonce */ 340 //PJ_STUN_SC_UNKNOWN_USERNAME = 436, /**< Unknown Username */ 341 //PJ_STUN_SC_NO_BINDING = 437, /**< No Binding. */ 342 #endif 340 343 PJ_STUN_SC_STALE_NONCE = 438, /**< Stale Nonce */ 341 344 PJ_STUN_SC_TRANSITIONING = 439, /**< Transitioning. */ … … 1092 1095 1093 1096 /** 1097 * Internal: set the padding character for string attribute. 1098 * The default padding character is PJ_STUN_STRING_ATTR_PAD_CHR. 1099 * 1100 * @return The previous padding character. 1101 */ 1102 PJ_DECL(int) pj_stun_set_padding_char(int chr); 1103 1104 1105 /** 1094 1106 * Create a generic STUN message. 1095 1107 * -
pjproject/trunk/pjnath/include/pjnath/types.h
r1126 r1439 143 143 * References for STUN: 144 144 * 145 * - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-rfc3489bis- 06.txt">146 * <B>draft-ietf-behave-rfc3489bis- 06</b></A>: Session Traversal145 * - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-rfc3489bis-10.txt"> 146 * <B>draft-ietf-behave-rfc3489bis-10</b></A>: Session Traversal 147 147 * Utilities for (NAT) (STUN), 148 148 * - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-turn-03.txt"> -
pjproject/trunk/pjnath/src/pjnath-test/stun.c
r1093 r1439 17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 */ 19 #include "test.h" 20 21 #define THIS_FILE "stun.c" 22 23 static pj_stun_msg* create1(pj_pool_t*); 24 static int verify1(pj_stun_msg*); 25 static int verify2(pj_stun_msg*); 26 static int verify5(pj_stun_msg*); 27 28 static struct test 29 { 30 const char *title; 31 char *pdu; 32 unsigned pdu_len; 33 pj_stun_msg* (*create)(pj_pool_t*); 34 pj_status_t expected_status; 35 int (*verify)(pj_stun_msg*); 36 } tests[] = 37 { 38 { 39 "Invalid message type", 40 "\x11\x01\x00\x00\x21\x12\xa4\x42" 41 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 42 20, 43 NULL, 44 PJNATH_EINSTUNMSGTYPE, 45 NULL 46 }, 47 { 48 "Short message (1) (partial header)", 49 "\x00\x01", 50 2, 51 NULL, 52 PJNATH_EINSTUNMSGLEN, 53 NULL 54 }, 55 { 56 "Short message (2) (partial header)", 57 "\x00\x01\x00\x00\x21\x12\xa4\x42" 58 "\x00\x00\x00\x00\x00\x00\x00\x00", 59 16, 60 NULL, 61 PJNATH_EINSTUNMSGLEN, 62 NULL 63 }, 64 { 65 "Short message (3), (missing attribute)", 66 "\x00\x01\x00\x08\x21\x12\xa4\x42" 67 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 68 20, 69 NULL, 70 PJNATH_EINSTUNMSGLEN, 71 NULL 72 }, 73 { 74 "Short message (4), (partial attribute header)", 75 "\x00\x01\x00\x08\x21\x12\xa4\x42" 76 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 77 "\x80\x28", 78 22, 79 NULL, 80 PJNATH_EINSTUNMSGLEN, 81 NULL 82 }, 83 { 84 "Short message (5), (partial attribute header)", 85 "\x00\x01\x00\x08\x21\x12\xa4\x42" 86 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 87 "\x80\x28\x00", 88 23, 89 NULL, 90 PJNATH_EINSTUNMSGLEN, 91 NULL 92 }, 93 { 94 "Short message (6), (partial attribute header)", 95 "\x00\x01\x00\x08\x21\x12\xa4\x42" 96 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 97 "\x80\x28\x00\x04", 98 24, 99 NULL, 100 PJNATH_EINSTUNMSGLEN, 101 NULL 102 }, 103 { 104 "Short message (7), (partial attribute body)", 105 "\x00\x01\x00\x08\x21\x12\xa4\x42" 106 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 107 "\x80\x28\x00\x04\x00\x00\x00", 108 27, 109 NULL, 110 PJNATH_EINSTUNMSGLEN, 111 NULL 112 }, 113 { 114 "Message length in header is too long", 115 "\x00\x01\xff\xff\x21\x12\xa4\x42" 116 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 117 "\x80\x28\x00\x04\x00\x00\x00", 118 27, 119 NULL, 120 PJNATH_EINSTUNMSGLEN, 121 NULL 122 }, 123 { 124 "Message length in header is shorter", 125 "\x00\x01\x00\x04\x21\x12\xa4\x42" 126 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 127 "\x80\x28\x00\x04\x00\x00\x00\x00", 128 28, 129 NULL, 130 PJNATH_EINSTUNMSGLEN, 131 NULL 132 }, 133 { 134 "Invalid magic", 135 "\x00\x01\x00\x08\x00\x12\xa4\x42" 136 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 137 "\x80\x28\x00\x04\x00\x00\x00\x00", 138 28, 139 NULL, 140 PJ_SUCCESS, 141 NULL 142 }, 143 { 144 "Character beyond message", 145 "\x00\x01\x00\x08\x21\x12\xa4\x42" 146 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 147 "\x80\x28\x00\x04\x00\x00\x00\x00\x0a", 148 29, 149 NULL, 150 PJNATH_EINSTUNMSGLEN, 151 NULL 152 }, 153 { 154 "Respond unknown mandatory attribute with 420 and " 155 "UNKNOWN-ATTRIBUTES attribute", 156 NULL, 157 0, 158 &create1, 159 0, 160 &verify1 161 }, 162 { 163 "Unknown but non-mandatory should be okay", 164 "\x00\x01\x00\x08\x21\x12\xa4\x42" 165 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 166 "\x80\xff\x00\x04\x00\x00\x00\x00", 167 28, 168 NULL, 169 PJ_SUCCESS, 170 &verify2 171 }, 172 { 173 "String attr length larger than message", 174 "\x00\x01\x00\x08\x00\x12\xa4\x42" 175 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 176 "\x00\x06\x00\xff\x00\x00\x00\x00", 177 28, 178 NULL, 179 PJNATH_ESTUNINATTRLEN, 180 NULL 181 }, 182 { 183 "Attribute other than FINGERPRINT after MESSAGE-INTEGRITY is allowed", 184 "\x00\x01\x00\x20\x21\x12\xa4\x42" 185 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 186 "\x00\x08\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 187 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // M-I 188 "\x80\x24\x00\x04\x00\x00\x00\x00", // REFRESH-INTERVAL 189 52, 190 NULL, 191 PJ_SUCCESS, 192 NULL 193 }, 194 { 195 "Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed", 196 "\x00\x01\x00\x28\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 "\x80\x28\x00\x04\xc7\xde\xdd\x65", // FINGERPRINT 202 60, 203 NULL, 204 PJ_SUCCESS, 205 &verify5 206 }, 207 { 208 "Attribute past FINGERPRINT is not allowed", 209 "\x00\x01\x00\x10\x21\x12\xa4\x42" 210 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 211 "\x80\x28\x00\x04\x00\x00\x00\x00" 212 "\x80\x24\x00\x04\x00\x00\x00\x00", 213 36, 214 NULL, 215 PJNATH_ESTUNFINGERPOS, 216 NULL 217 } 218 }; 219 220 static const char *err(pj_status_t status) 221 { 222 static char errmsg[PJ_ERR_MSG_SIZE]; 223 pj_strerror(status, errmsg, sizeof(errmsg)); 224 return errmsg; 225 } 226 227 static const pj_str_t USERNAME = {"user", 4}; 228 static const pj_str_t PASSWORD = {"password", 8}; 19 229 20 230 static int decode_test(void) 21 231 { 22 /* Invalid message type */ 23 24 /* Short message */ 25 26 /* Long, random message */ 27 28 /* Message length in header is shorter */ 29 30 /* Message length in header is longer */ 31 32 /* Invalid magic */ 33 34 /* Attribute length is not valid */ 35 36 /* Unknown mandatory attribute type should generate error */ 37 38 /* Unknown but non-mandatory should be okay */ 39 40 /* String/binary attribute length is larger than the message */ 41 42 /* Valid message with MESSAGE-INTEGRITY */ 43 44 /* Valid message with FINGERPRINT */ 45 46 /* Valid message with MESSAGE-INTEGRITY and FINGERPRINT */ 47 48 /* Another attribute not FINGERPRINT exists after MESSAGE-INTEGRITY */ 49 50 /* Another attribute exists after FINGERPRINT */ 232 unsigned i; 233 pj_pool_t *pool; 234 int rc = 0; 235 236 pool = pj_pool_create(mem, "decode_test", 1024, 1024, NULL); 237 238 PJ_LOG(3,(THIS_FILE, " STUN decode test")); 239 240 for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) { 241 struct test *t = &tests[i]; 242 pj_stun_msg *msg, *msg2; 243 pj_uint8_t buf[1500]; 244 pj_str_t key; 245 unsigned len; 246 pj_status_t status; 247 248 PJ_LOG(3,(THIS_FILE, " %s", t->title)); 249 250 if (t->pdu) { 251 status = pj_stun_msg_decode(pool, (pj_uint8_t*)t->pdu, t->pdu_len, 252 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 253 &msg, NULL, NULL); 254 255 /* Check expected decode result */ 256 if (t->expected_status != status) { 257 PJ_LOG(1,(THIS_FILE, " expecting status %d, got %d", 258 t->expected_status, status)); 259 rc = -10; 260 goto on_return; 261 } 262 263 } else { 264 msg = t->create(pool); 265 status = PJ_SUCCESS; 266 } 267 268 if (status != PJ_SUCCESS) 269 continue; 270 271 /* Try to encode message */ 272 pj_stun_create_key(pool, &key, NULL, &USERNAME, &PASSWORD); 273 status = pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len); 274 if (status != PJ_SUCCESS) { 275 PJ_LOG(1,(THIS_FILE, " encode error: %s", err(status))); 276 rc = -40; 277 goto on_return; 278 } 279 280 /* Try to decode it once more */ 281 status = pj_stun_msg_decode(pool, buf, len, 282 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 283 &msg2, NULL, NULL); 284 if (status != PJ_SUCCESS) { 285 PJ_LOG(1,(THIS_FILE, " subsequent decoding failed: %s", err(status))); 286 rc = -50; 287 goto on_return; 288 } 289 290 /* Verify */ 291 if (t->verify) { 292 rc = t->verify(msg); 293 if (rc != 0) { 294 goto on_return; 295 } 296 } 297 } 298 299 on_return: 300 pj_pool_release(pool); 301 if (rc == 0) 302 PJ_LOG(3,(THIS_FILE, "...success!")); 303 return rc; 304 } 305 306 /* Create 420 response */ 307 static pj_stun_msg* create1(pj_pool_t *pool) 308 { 309 char *pdu = "\x00\x01\x00\x08\x21\x12\xa4\x42" 310 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 311 "\x00\xff\x00\x04\x00\x00\x00\x00"; 312 unsigned pdu_len = 28; 313 pj_stun_msg *msg, *res; 314 pj_status_t status; 315 316 status = pj_stun_msg_decode(pool, (pj_uint8_t*)pdu, pdu_len, 317 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 318 &msg, NULL, &res); 319 pj_assert(status != PJ_SUCCESS); 320 pj_assert(res != NULL); 321 322 return res; 323 } 324 325 /* Error response MUST have ERROR-CODE attribute */ 326 /* 420 response MUST contain UNKNOWN-ATTRIBUTES */ 327 static int verify1(pj_stun_msg *msg) 328 { 329 pj_stun_errcode_attr *aerr; 330 pj_stun_unknown_attr *aunk; 331 332 if (!PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) { 333 PJ_LOG(1,(THIS_FILE, " expecting error message")); 334 return -100; 335 } 336 337 aerr = (pj_stun_errcode_attr*) 338 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0); 339 if (aerr == NULL) { 340 PJ_LOG(1,(THIS_FILE, " missing ERROR-CODE attribute")); 341 return -110; 342 } 343 344 if (aerr->err_code != 420) { 345 PJ_LOG(1,(THIS_FILE, " expecting 420 error")); 346 return -120; 347 } 348 349 aunk = (pj_stun_unknown_attr*) 350 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, 0); 351 if (aunk == NULL) { 352 PJ_LOG(1,(THIS_FILE, " missing UNKNOWN-ATTRIBUTE attribute")); 353 return -130; 354 } 355 356 if (aunk->attr_count != 1) { 357 PJ_LOG(1,(THIS_FILE, " expecting one unknown attribute")); 358 return -140; 359 } 360 361 if (aunk->attrs[0] != 0xff) { 362 PJ_LOG(1,(THIS_FILE, " expecting 0xff as unknown attribute")); 363 return -150; 364 } 51 365 52 366 return 0; 53 367 } 368 369 /* Attribute count should be zero since unknown attribute is not parsed */ 370 static int verify2(pj_stun_msg *msg) 371 { 372 if (msg->attr_count != 0) { 373 PJ_LOG(1,(THIS_FILE, " expecting zero attribute count")); 374 return -200; 375 } 376 return 0; 377 } 378 379 380 /* Attribute between MESSAGE-INTEGRITY and FINGERPRINT is allowed */ 381 static int verify5(pj_stun_msg *msg) 382 { 383 if (msg->attr_count != 3) { 384 PJ_LOG(1,(THIS_FILE, " expecting 3 attribute count")); 385 return -500; 386 } 387 388 if (msg->attr[0]->type != PJ_STUN_ATTR_MESSAGE_INTEGRITY) { 389 PJ_LOG(1,(THIS_FILE, " expecting MESSAGE-INTEGRITY")); 390 return -510; 391 } 392 if (msg->attr[1]->type != PJ_STUN_ATTR_REFRESH_INTERVAL) { 393 PJ_LOG(1,(THIS_FILE, " expecting REFRESH-INTERVAL")); 394 return -520; 395 } 396 if (msg->attr[2]->type != PJ_STUN_ATTR_FINGERPRINT) { 397 PJ_LOG(1,(THIS_FILE, " expecting FINGERPRINT")); 398 return -530; 399 } 400 401 return 0; 402 } 403 54 404 55 405 static int decode_verify(void) … … 108 458 } 109 459 460 typedef struct test_vector test_vector; 461 462 static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v); 463 static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v); 464 465 enum 466 { 467 USE_MESSAGE_INTEGRITY = 1, 468 USE_FINGERPRINT = 2 469 }; 470 471 struct test_vector 472 { 473 unsigned msg_type; 474 char *tsx_id; 475 char *pdu; 476 unsigned pdu_len; 477 unsigned options; 478 char *username; 479 char *password; 480 pj_stun_msg* (*create)(pj_pool_t*, test_vector*); 481 } test_vectors[] = 482 { 483 { 484 PJ_STUN_BINDING_REQUEST, 485 "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae", 486 "\x00\x01\x00\x44\x21\x12\xa4\x42\xb7\xe7" 487 "\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae" 488 "\x00\x24\x00\x04\x6e\x00\x01\xff\x80\x29" 489 "\x00\x08\x93\x2f\xf9\xb1\x51\x26\x3b\x36" 490 "\x00\x06\x00\x09\x65\x76\x74\x6a\x3a\x68" 491 "\x36\x76\x59\x20\x20\x20\x00\x08\x00\x14" 492 "\x62\x4e\xeb\xdc\x3c\xc9\x2d\xd8\x4b\x74" 493 "\xbf\x85\xd1\xc0\xf5\xde\x36\x87\xbd\x33" 494 "\x80\x28\x00\x04\xad\x8a\x85\xff", 495 88, 496 USE_MESSAGE_INTEGRITY | USE_FINGERPRINT, 497 "evtj:h6vY", 498 "VOkJxbRl1RmTxUk/WvJxBt", 499 &create_msgint1 500 }, 501 { 502 PJ_STUN_BINDING_RESPONSE, 503 "\xb7\xe7\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae", 504 "\x01\x01\x00\x3c\x21\x12\xa4\x42\xb7\xe7" 505 "\xa7\x01\xbc\x34\xd6\x86\xfa\x87\xdf\xae" 506 "\x80\x22\x00\x0b\x74\x65\x73\x74\x20\x76" 507 "\x65\x63\x74\x6f\x72\x20\x00\x20\x00\x08" 508 "\x00\x01\xa1\x47\x5e\x12\xa4\x43\x00\x08" 509 "\x00\x14\xab\x4e\x53\x29\x61\x00\x08\x4c" 510 "\x89\xf2\x7c\x69\x30\x33\x5c\xa3\x58\x14" 511 "\xea\x90\x80\x28\x00\x04\xae\x25\x8d\xf2", 512 80, 513 USE_MESSAGE_INTEGRITY | USE_FINGERPRINT, 514 "evtj:h6vY", 515 "VOkJxbRl1RmTxUk/WvJxBt", 516 &create_msgint2 517 } 518 }; 519 520 521 static char* print_binary(const pj_uint8_t *data, unsigned data_len) 522 { 523 static char buf[1500]; 524 unsigned length = sizeof(buf); 525 char *p = buf; 526 unsigned i; 527 528 for (i=0; i<data_len;) { 529 unsigned j; 530 531 pj_ansi_snprintf(p, 1500-(p-buf), 532 "%04d-%04d ", 533 i, (i+20 < data_len) ? i+20 : data_len); 534 p += 12; 535 536 for (j=0; j<20 && i<data_len && p<(buf+length-10); ++j, ++i) { 537 pj_ansi_sprintf(p, "%02x ", (*data) & 0xFF); 538 p += 3; 539 data++; 540 } 541 542 pj_ansi_sprintf(p, "\n"); 543 p++; 544 } 545 546 return buf; 547 } 548 549 static int cmp_buf(const pj_uint8_t *s1, const pj_uint8_t *s2, unsigned len) 550 { 551 unsigned i; 552 for (i=0; i<len; ++i) { 553 if (s1[i] != s2[i]) 554 return i; 555 } 556 557 return -1; 558 } 559 560 static int fingerprint_test_vector() 561 { 562 pj_pool_t *pool; 563 pj_status_t status; 564 unsigned i; 565 int rc = 0; 566 567 PJ_LOG(3,(THIS_FILE, " STUN message test vectors")); 568 569 pool = pj_pool_create(mem, "fingerprint", 1024, 1024, NULL); 570 571 for (i=0; i<PJ_ARRAY_SIZE(test_vectors); ++i) { 572 struct test_vector *v; 573 pj_stun_msg *ref_msg, *msg; 574 unsigned parsed_len; 575 unsigned len, pos; 576 pj_uint8_t buf[1500]; 577 char print[1500]; 578 pj_str_t key; 579 580 PJ_LOG(3,(THIS_FILE, " Running test %d/%d", i, 581 PJ_ARRAY_SIZE(test_vectors))); 582 583 v = &test_vectors[i]; 584 585 /* Print reference message */ 586 PJ_LOG(4,(THIS_FILE, "Reference message PDU:\n%s", 587 print_binary((pj_uint8_t*)v->pdu, v->pdu_len))); 588 589 /* Try to parse the reference message first */ 590 status = pj_stun_msg_decode(pool, (pj_uint8_t*)v->pdu, v->pdu_len, 591 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 592 &ref_msg, &parsed_len, NULL); 593 if (status != PJ_SUCCESS) { 594 PJ_LOG(1,(THIS_FILE, " Error decoding reference message")); 595 rc = -1010; 596 goto on_return; 597 } 598 599 if (parsed_len != v->pdu_len) { 600 PJ_LOG(1,(THIS_FILE, " Parsed len error")); 601 rc = -1020; 602 goto on_return; 603 } 604 605 /* Print the reference message */ 606 pj_stun_msg_dump(ref_msg, print, sizeof(print), NULL); 607 PJ_LOG(4,(THIS_FILE, "Reference message:\n%s", print)); 608 609 /* Create our message */ 610 msg = v->create(pool, v); 611 612 /* Encode message */ 613 if (v->options & USE_MESSAGE_INTEGRITY) { 614 pj_str_t s1, s2; 615 616 pj_stun_create_key(pool, &key, NULL, pj_cstr(&s1, v->username), 617 pj_cstr(&s2, v->password)); 618 pj_stun_msg_encode(msg, buf, sizeof(buf), 0, &key, &len); 619 620 } else { 621 pj_stun_msg_encode(msg, buf, sizeof(buf), 0, NULL, &len); 622 } 623 624 /* Print our raw message */ 625 PJ_LOG(4,(THIS_FILE, "Message PDU:\n%s", 626 print_binary((pj_uint8_t*)buf, len))); 627 628 /* Print our message */ 629 pj_stun_msg_dump(msg, print, sizeof(print), NULL); 630 PJ_LOG(4,(THIS_FILE, "Message is:\n%s", print)); 631 632 /* Compare message length */ 633 if (len != v->pdu_len) { 634 PJ_LOG(1,(THIS_FILE, " Message length mismatch")); 635 rc = -1050; 636 goto on_return; 637 } 638 639 pos = cmp_buf(buf, (const pj_uint8_t*)v->pdu, len); 640 if (pos != -1) { 641 PJ_LOG(1,(THIS_FILE, " Message mismatch at byte %d", pos)); 642 rc = -1060; 643 goto on_return; 644 } 645 646 /* Authenticate the request/response */ 647 if (v->options & USE_MESSAGE_INTEGRITY) { 648 if (PJ_STUN_IS_REQUEST(msg->hdr.type)) { 649 pj_stun_auth_cred cred; 650 pj_status_t status; 651 652 pj_bzero(&cred, sizeof(cred)); 653 cred.type = PJ_STUN_AUTH_CRED_STATIC; 654 cred.data.static_cred.username = pj_str(v->username); 655 cred.data.static_cred.data = pj_str(v->password); 656 657 status = pj_stun_authenticate_request(buf, len, msg, 658 &cred, pool, NULL); 659 if (status != PJ_SUCCESS) { 660 char errmsg[PJ_ERR_MSG_SIZE]; 661 pj_strerror(status, errmsg, sizeof(errmsg)); 662 PJ_LOG(1,(THIS_FILE, 663 " Request authentication failed: %s", 664 errmsg)); 665 rc = -1070; 666 goto on_return; 667 } 668 669 } else if (PJ_STUN_IS_RESPONSE(msg->hdr.type)) { 670 pj_status_t status; 671 status = pj_stun_authenticate_response(buf, len, msg, &key); 672 if (status != PJ_SUCCESS) { 673 char errmsg[PJ_ERR_MSG_SIZE]; 674 pj_strerror(status, errmsg, sizeof(errmsg)); 675 PJ_LOG(1,(THIS_FILE, 676 " Response authentication failed: %s", 677 errmsg)); 678 rc = -1080; 679 goto on_return; 680 } 681 } 682 } 683 } 684 685 686 on_return: 687 pj_pool_release(pool); 688 return rc; 689 } 690 691 static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v) 692 { 693 pj_stun_msg *msg; 694 pj_timestamp u64; 695 pj_str_t s1; 696 697 pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC, 698 (pj_uint8_t*)v->tsx_id, &msg); 699 700 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_PRIORITY, 0x6e0001ff); 701 u64.u32.hi = 0x932ff9b1; 702 u64.u32.lo = 0x51263b36; 703 pj_stun_msg_add_uint64_attr(pool, msg, PJ_STUN_ATTR_ICE_CONTROLLED, 704 &u64); 705 706 pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_USERNAME, 707 pj_cstr(&s1, v->username)); 708 709 pj_stun_msg_add_msgint_attr(pool, msg); 710 711 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0); 712 713 return msg; 714 } 715 716 static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v) 717 { 718 pj_stun_msg *msg; 719 pj_sockaddr_in mapped_addr; 720 pj_str_t s1; 721 722 pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC, 723 (pj_uint8_t*)v->tsx_id, &msg); 724 725 pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SERVER, 726 pj_cstr(&s1, "test vector")); 727 728 pj_sockaddr_in_init(&mapped_addr, pj_cstr(&s1, "127.0.0.1"), 32853); 729 pj_stun_msg_add_sockaddr_attr(pool, msg, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 730 PJ_TRUE, &mapped_addr, 731 sizeof(pj_sockaddr_in)); 732 733 pj_stun_msg_add_msgint_attr(pool, msg); 734 pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0); 735 736 return msg; 737 } 738 110 739 111 740 int stun_test(void) 112 741 { 113 decode_verify(); 114 decode_test(); 115 auth_test(); 116 return 0; 117 } 118 742 int pad, rc; 743 744 pad = pj_stun_set_padding_char(32); 745 746 rc = decode_test(); 747 if (rc != 0) 748 goto on_return; 749 750 rc = decode_verify(); 751 if (rc != 0) 752 goto on_return; 753 754 rc = auth_test(); 755 if (rc != 0) 756 goto on_return; 757 758 rc = fingerprint_test_vector(); 759 if (rc != 0) 760 goto on_return; 761 762 on_return: 763 pj_stun_set_padding_char(pad); 764 return rc; 765 } 766 -
pjproject/trunk/pjnath/src/pjnath-test/test.c
r1288 r1439 67 67 pjnath_init(); 68 68 69 #if INCLUDE_STUN_TEST 70 DO_TEST(stun_test()); 71 #endif 72 69 73 #if INCLUDE_ICE_TEST 70 74 DO_TEST(ice_test()); -
pjproject/trunk/pjnath/src/pjnath-test/test.h
r1093 r1439 21 21 #include <pjnath.h> 22 22 23 #define INCLUDE_STUN_TEST 1 23 24 #define INCLUDE_ICE_TEST 1 24 25 26 extern int stun_test(void); 25 27 extern int ice_test(void); 26 28 extern int test_main(void); -
pjproject/trunk/pjnath/src/pjnath/ice_session.c
r1435 r1439 490 490 /* Verify username */ 491 491 if (pj_strcmp(username, &ice->tx_uname) != 0) 492 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UN KNOWN_USERNAME);492 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 493 493 *data_type = 0; 494 494 *data = ice->tx_pass; … … 508 508 pos = (const char*)pj_memchr(username->ptr, ':', username->slen); 509 509 if (pos == NULL) 510 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UN KNOWN_USERNAME);510 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 511 511 512 512 ufrag.ptr = (char*)username->ptr; … … 514 514 515 515 if (pj_strcmp(&ufrag, &ice->rx_ufrag) != 0) 516 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UN KNOWN_USERNAME);516 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 517 517 518 518 *data_type = 0; -
pjproject/trunk/pjnath/src/pjnath/stun_auth.c
r1374 r1439 60 60 61 61 62 PJ_INLINE(void) PUT_VAL16(pj_uint8_t *buf, unsigned pos, pj_uint16_t hval) 63 { 64 buf[pos+0] = (pj_uint8_t) ((hval & 0xFF00) >> 8); 65 buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF) >> 0); 66 } 67 68 62 69 /* Send 401 response */ 63 70 static pj_status_t create_challenge(pj_pool_t *pool, 64 71 const pj_stun_msg *msg, 65 72 int err_code, 66 const pj_str_t *err_msg,73 const char *errstr, 67 74 const pj_str_t *realm, 68 75 const pj_str_t *nonce, … … 71 78 pj_stun_msg *response; 72 79 pj_str_t tmp_nonce; 80 pj_str_t err_msg; 73 81 pj_status_t rc; 74 82 75 rc = pj_stun_msg_create_response(pool, msg, 76 err_code, err_msg, &response); 83 rc = pj_stun_msg_create_response(pool, msg, err_code, 84 (errstr?pj_cstr(&err_msg, errstr):NULL), 85 &response); 77 86 if (rc != PJ_SUCCESS) 78 87 return rc; … … 117 126 pj_str_t realm, nonce, password; 118 127 const pj_stun_msgint_attr *amsgi; 119 unsigned amsgi_pos; 128 unsigned i, amsgi_pos; 129 pj_bool_t has_attr_beyond_mi; 120 130 const pj_stun_username_attr *auser; 121 131 pj_bool_t username_ok; … … 139 149 p_response = NULL; 140 150 141 /* Get realm and nonce */151 /* Get realm and nonce from credential */ 142 152 realm.slen = nonce.slen = 0; 143 153 if (cred->type == PJ_STUN_AUTH_CRED_STATIC) { … … 154 164 } 155 165 156 /* First check that MESSAGE-INTEGRITY is present */ 157 amsgi = (const pj_stun_msgint_attr*) 158 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0); 166 /* Look for MESSAGE-INTEGRITY while counting the position */ 167 amsgi_pos = 0; 168 has_attr_beyond_mi = PJ_FALSE; 169 amsgi = NULL; 170 for (i=0; i<msg->attr_count; ++i) { 171 if (msg->attr[i]->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { 172 amsgi = (const pj_stun_msgint_attr*) msg->attr[i]; 173 } else if (amsgi) { 174 has_attr_beyond_mi = PJ_TRUE; 175 break; 176 } else { 177 amsgi_pos += ((msg->attr[i]->length+3) & ~0x03) + 4; 178 } 179 } 180 159 181 if (amsgi == NULL) { 182 /* According to rfc3489bis-10 Sec 10.1.2/10.2.2, we should return 400 183 for short term, and 401 for long term. 184 The rule has been changed from rfc3489bis-06 185 */ 186 int code; 187 188 code = realm.slen ? PJ_STUN_SC_UNAUTHORIZED : PJ_STUN_SC_BAD_REQUEST; 160 189 if (p_response) { 161 create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, NULL,190 create_challenge(pool, msg, code, NULL, 162 191 &realm, &nonce, p_response); 163 192 } 164 return PJ_STATUS_FROM_STUN_CODE( PJ_STUN_SC_INTEGRITY_CHECK_FAILURE);193 return PJ_STATUS_FROM_STUN_CODE(code); 165 194 } 166 195 … … 169 198 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0); 170 199 if (auser == NULL) { 200 /* According to rfc3489bis-10 Sec 10.1.2/10.2.2, we should return 400 201 for both short and long term, since M-I is present. 202 The rule has been changed from rfc3489bis-06 203 */ 204 int code = PJ_STUN_SC_BAD_REQUEST; 171 205 if (p_response) { 172 create_challenge(pool, msg, PJ_STUN_SC_MISSING_USERNAME, NULL,206 create_challenge(pool, msg, code, "Missing USERNAME", 173 207 &realm, &nonce, p_response); 174 208 } 175 return PJ_STATUS_FROM_STUN_CODE( PJ_STUN_SC_MISSING_USERNAME);209 return PJ_STATUS_FROM_STUN_CODE(code); 176 210 } 177 211 … … 201 235 if (!username_ok) { 202 236 /* Username mismatch */ 237 /* According to rfc3489bis-10 Sec 10.1.2/10.2.2, we should 238 * return 401 239 */ 203 240 if (p_response) { 204 create_challenge(pool, msg, PJ_STUN_SC_UN KNOWN_USERNAME, NULL,241 create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, NULL, 205 242 &realm, &nonce, p_response); 206 243 } 207 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UN KNOWN_USERNAME);244 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 208 245 } 209 246 … … 217 254 /* Long term credential is required and REALM is not present */ 218 255 if (p_response) { 219 create_challenge(pool, msg, PJ_STUN_SC_MISSING_REALM, NULL, 256 create_challenge(pool, msg, PJ_STUN_SC_BAD_REQUEST, 257 "Missing REALM", 220 258 &realm, &nonce, p_response); 221 259 } 222 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ MISSING_REALM);260 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST); 223 261 224 262 } else if (realm.slen != 0 && arealm != NULL) { … … 228 266 if (anonce == NULL && nonce.slen) { 229 267 if (p_response) { 230 create_challenge(pool, msg, PJ_STUN_SC_ MISSING_NONCE,231 NULL, &realm, &nonce, p_response);268 create_challenge(pool, msg, PJ_STUN_SC_BAD_REQUEST, 269 "Missing NONCE", &realm, &nonce, p_response); 232 270 } 233 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ MISSING_NONCE);271 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST); 234 272 } 235 273 … … 238 276 /* REALM doesn't match */ 239 277 if (p_response) { 240 create_challenge(pool, msg, PJ_STUN_SC_ MISSING_REALM,241 NULL, &realm, &nonce, p_response);278 create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, 279 "Invalid REALM", &realm, &nonce, p_response); 242 280 } 243 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ MISSING_REALM);281 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 244 282 } 245 283 … … 261 299 if (nonce.slen != 0) { 262 300 if (p_response) { 263 create_challenge(pool, msg, PJ_STUN_SC_ MISSING_NONCE,264 NULL, &realm, &nonce, p_response);301 create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, 302 "NONCE required", &realm, &nonce, p_response); 265 303 } 266 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ MISSING_NONCE);304 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 267 305 } 268 306 } … … 295 333 NULL, &realm, &nonce, p_response); 296 334 } 297 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_NONCE); 298 } 299 } 300 301 /* Get the position of MESSAGE-INTEGRITY in the packet */ 302 amsgi_pos = 20+msg->hdr.length-24; 303 if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { 304 /* Found MESSAGE-INTEGRITY as the last attribute */ 305 } else { 306 amsgi_pos = 0; 307 } 308 309 if (amsgi_pos==0) { 310 amsgi_pos = 20+msg->hdr.length-8-24; 311 if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { 312 /* Found MESSAGE-INTEGRITY before FINGERPRINT */ 313 } else { 314 amsgi_pos = 0; 315 } 316 } 317 318 if (amsgi_pos==0) { 319 pj_assert(!"Unable to find MESSAGE-INTEGRITY in the message!"); 320 return PJ_EBUG; 335 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_STALE_NONCE); 336 } 321 337 } 322 338 … … 324 340 pj_stun_create_key(pool, &key, &realm, &auser->value, &password); 325 341 326 /* Now calculate HMAC of the message, adding zero padding if necessary 327 * to make the input 64 bytes aligned. 342 /* Now calculate HMAC of the message. */ 343 pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key.ptr, key.slen); 344 345 /* First calculate HMAC for the header. 346 * The calculation is different depending on whether FINGERPRINT attribute 347 * is present in the message. 328 348 */ 329 pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key.ptr, key.slen); 330 pj_hmac_sha1_update(&ctx, pkt, amsgi_pos); 331 if (amsgi_pos & 63) { 332 pj_uint8_t zeroes[64]; 333 pj_bzero(zeroes, sizeof(zeroes)); 334 pj_hmac_sha1_update(&ctx, zeroes, 64-(amsgi_pos & 63)); 335 } 349 if (has_attr_beyond_mi) { 350 pj_uint8_t hdr_copy[20]; 351 pj_memcpy(hdr_copy, pkt, 20); 352 PUT_VAL16(hdr_copy, 2, (pj_uint16_t)(amsgi_pos + 24)); 353 pj_hmac_sha1_update(&ctx, hdr_copy, 20); 354 } else { 355 pj_hmac_sha1_update(&ctx, pkt, 20); 356 } 357 358 /* Now update with the message body */ 359 pj_hmac_sha1_update(&ctx, pkt+20, amsgi_pos); 360 // This is no longer necessary as per rfc3489bis-08 361 //if (amsgi_pos & 0x3F) { 362 // pj_uint8_t zeroes[64]; 363 // pj_bzero(zeroes, sizeof(zeroes)); 364 // pj_hmac_sha1_update(&ctx, zeroes, 64-(amsgi_pos & 0x3F)); 365 //} 336 366 pj_hmac_sha1_final(&ctx, digest); 367 337 368 338 369 /* Compare HMACs */ 339 370 if (pj_memcmp(amsgi->hmac, digest, 20)) { 340 371 /* HMAC value mismatch */ 372 /* According to rfc3489bis-10 Sec 10.1.2 we should return 401 */ 341 373 if (p_response) { 342 create_challenge(pool, msg, PJ_STUN_SC_ INTEGRITY_CHECK_FAILURE,374 create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, 343 375 NULL, &realm, &nonce, p_response); 344 376 } 345 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ INTEGRITY_CHECK_FAILURE);377 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 346 378 } 347 379 … … 382 414 case PJ_STUN_SC_BAD_REQUEST: /* 400 (Bad Request) */ 383 415 case PJ_STUN_SC_UNAUTHORIZED: /* 401 (Unauthorized) */ 384 case PJ_STUN_SC_STALE_CREDENTIALS:/* 430 (Stale Credential) */385 case PJ_STUN_SC_MISSING_USERNAME: /* 432 (Missing Username) */386 case PJ_STUN_SC_MISSING_REALM: /* 434 (Missing Realm) */387 case PJ_STUN_SC_UNKNOWN_USERNAME: /* 436 (Unknown Username) */388 case PJ_STUN_SC_INTEGRITY_CHECK_FAILURE:/* 431 (Integrity Check Fail)*/416 //case PJ_STUN_SC_STALE_CREDENTIALS: /* 430 (Stale Credential) */ 417 //case PJ_STUN_SC_MISSING_USERNAME: /* 432 (Missing Username) */ 418 //case PJ_STUN_SC_MISSING_REALM: /* 434 (Missing Realm) */ 419 //case PJ_STUN_SC_UNKNOWN_USERNAME: /* 436 (Unknown Username) */ 420 //case PJ_STUN_SC_INTEGRITY_CHECK_FAILURE:/* 431 (Integrity Check Fail) */ 389 421 return PJ_FALSE; 390 422 default: … … 401 433 { 402 434 const pj_stun_msgint_attr *amsgi; 403 unsigned amsgi_pos; 435 unsigned i, amsgi_pos; 436 pj_bool_t has_attr_beyond_mi; 404 437 pj_hmac_sha1_context ctx; 405 438 pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE]; … … 411 444 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0); 412 445 if (amsgi == NULL) { 413 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ INTEGRITY_CHECK_FAILURE);446 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 414 447 } 415 448 … … 420 453 } 421 454 422 /* Get the position of MESSAGE-INTEGRITY in the packet */ 423 amsgi_pos = 20+msg->hdr.length-24; 424 if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { 425 /* Found MESSAGE-INTEGRITY as the last attribute */ 455 /* Look for MESSAGE-INTEGRITY while counting the position */ 456 amsgi_pos = 0; 457 has_attr_beyond_mi = PJ_FALSE; 458 amsgi = NULL; 459 for (i=0; i<msg->attr_count; ++i) { 460 if (msg->attr[i]->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { 461 amsgi = (const pj_stun_msgint_attr*) msg->attr[i]; 462 } else if (amsgi) { 463 has_attr_beyond_mi = PJ_TRUE; 464 break; 465 } else { 466 amsgi_pos += ((msg->attr[i]->length+3) & ~0x03) + 4; 467 } 468 } 469 470 if (amsgi == NULL) { 471 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST); 472 } 473 474 /* Now calculate HMAC of the message. */ 475 pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key->ptr, key->slen); 476 477 /* First calculate HMAC for the header. 478 * The calculation is different depending on whether FINGERPRINT attribute 479 * is present in the message. 480 */ 481 if (has_attr_beyond_mi) { 482 pj_uint8_t hdr_copy[20]; 483 pj_memcpy(hdr_copy, pkt, 20); 484 PUT_VAL16(hdr_copy, 2, (pj_uint16_t)(amsgi_pos+24)); 485 pj_hmac_sha1_update(&ctx, hdr_copy, 20); 426 486 } else { 427 amsgi_pos = 0; 428 } 429 430 if (amsgi_pos==0) { 431 /* Check that message length is valid */ 432 if (msg->hdr.length < 32) { 433 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE); 434 } 435 436 amsgi_pos = 20+msg->hdr.length-8-24; 437 if (GET_VAL16(pkt, amsgi_pos) == PJ_STUN_ATTR_MESSAGE_INTEGRITY) { 438 /* Found MESSAGE-INTEGRITY before FINGERPRINT */ 439 } else { 440 amsgi_pos = 0; 441 } 442 } 443 444 if (amsgi_pos==0) { 445 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE); 446 } 447 448 /* Now calculate HMAC of the message, adding zero padding if necessary 449 * to make the input 64 bytes aligned. 450 */ 451 pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key->ptr, key->slen); 452 pj_hmac_sha1_update(&ctx, pkt, amsgi_pos); 453 if (amsgi_pos & 0x3F) { 454 pj_uint8_t zeroes[64]; 455 pj_bzero(zeroes, sizeof(zeroes)); 456 pj_hmac_sha1_update(&ctx, zeroes, 64-(amsgi_pos & 0x3F)); 457 } 487 pj_hmac_sha1_update(&ctx, pkt, 20); 488 } 489 490 /* Now update with the message body */ 491 pj_hmac_sha1_update(&ctx, pkt+20, amsgi_pos); 492 // This is no longer necessary as per rfc3489bis-08 493 //if (amsgi_pos & 0x3F) { 494 // pj_uint8_t zeroes[64]; 495 // pj_bzero(zeroes, sizeof(zeroes)); 496 // pj_hmac_sha1_update(&ctx, zeroes, 64-(amsgi_pos & 0x3F)); 497 //} 458 498 pj_hmac_sha1_final(&ctx, digest); 459 499 … … 461 501 if (pj_memcmp(amsgi->hmac, digest, 20)) { 462 502 /* HMAC value mismatch */ 463 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ INTEGRITY_CHECK_FAILURE);503 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 464 504 } 465 505 -
pjproject/trunk/pjnath/src/pjnath/stun_msg.c
r1410 r1439 32 32 #define STUN_XOR_FINGERPRINT 0x5354554eL 33 33 34 static int padding_char; 35 34 36 static const char *stun_method_names[] = 35 37 { … … 55 57 { PJ_STUN_SC_UNAUTHORIZED, "Unauthorized"}, 56 58 { PJ_STUN_SC_UNKNOWN_ATTRIBUTE, "Unknown Attribute"}, 57 { PJ_STUN_SC_STALE_CREDENTIALS, "Stale Credentials"},58 { PJ_STUN_SC_INTEGRITY_CHECK_FAILURE,"Integrity Check Failure"},59 { PJ_STUN_SC_MISSING_USERNAME, "Missing Username"},60 { PJ_STUN_SC_USE_TLS, "Use TLS"},61 { PJ_STUN_SC_MISSING_REALM,"Missing Realm"},62 { PJ_STUN_SC_MISSING_NONCE,"Missing Nonce"},63 { PJ_STUN_SC_UNKNOWN_USERNAME, "Unknown Username"},64 { PJ_STUN_SC_NO_BINDING, "No Binding"},59 //{ PJ_STUN_SC_STALE_CREDENTIALS, "Stale Credentials"}, 60 //{ PJ_STUN_SC_INTEGRITY_CHECK_FAILURE, "Integrity Check Failure"}, 61 //{ PJ_STUN_SC_MISSING_USERNAME, "Missing Username"}, 62 //{ PJ_STUN_SC_USE_TLS, "Use TLS"}, 63 //{ PJ_STUN_SC_MISSING_REALM, "Missing Realm"}, 64 //{ PJ_STUN_SC_MISSING_NONCE, "Missing Nonce"}, 65 //{ PJ_STUN_SC_UNKNOWN_USERNAME, "Unknown Username"}, 66 //{ PJ_STUN_SC_NO_BINDING, "No Binding"}, 65 67 { PJ_STUN_SC_STALE_NONCE, "Stale Nonce"}, 66 68 { PJ_STUN_SC_TRANSITIONING, "Active Destination Already Set"}, … … 569 571 570 572 573 /* 574 * Set padding character. 575 */ 576 PJ_DEF(int) pj_stun_set_padding_char(int chr) 577 { 578 int old_pad = padding_char; 579 padding_char = chr; 580 return old_pad; 581 } 582 583 571 584 ////////////////////////////////////////////////////////////////////////////// 572 585 … … 900 913 /* Copy the string */ 901 914 pj_memcpy(buf+ATTR_HDR_LEN, ca->value.ptr, ca->value.slen); 915 916 /* Add padding character, if string is not 4-bytes aligned. */ 917 if (ca->value.slen & 0x03) { 918 pj_uint8_t pad[3]; 919 pj_memset(pad, padding_char, sizeof(pad)); 920 pj_memcpy(buf+ATTR_HDR_LEN+ca->value.slen, pad, 921 4-(ca->value.slen & 0x03)); 922 } 902 923 903 924 /* Done */ … … 1379 1400 * attributes MUST be repeated in the list. 1380 1401 */ 1402 /* No longer necessary 1381 1403 if ((attr_cnt & 0x01)) { 1382 1404 attr->attrs[attr_cnt] = attr_array[attr_cnt-1]; 1383 1405 } 1384 1385 *p_attr = NULL; 1406 */ 1407 1408 *p_attr = attr; 1386 1409 1387 1410 return PJ_SUCCESS; … … 1634 1657 ((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len)) 1635 1658 { 1659 return PJNATH_EINSTUNMSGLEN; 1660 } 1661 1662 /* STUN message is always padded to the nearest 4 bytes, thus 1663 * the last two bits of the length field are always zero. 1664 */ 1665 if ((msg_len & 0x03) != 0) { 1636 1666 return PJNATH_EINSTUNMSGLEN; 1637 1667 } … … 1879 1909 has_fingerprint = PJ_TRUE; 1880 1910 } else { 1881 if (has_ msg_int || has_fingerprint) {1911 if (has_fingerprint) { 1882 1912 /* Another attribute is found which is not FINGERPRINT 1883 * after FINGERPRINT or MESSAGE-INTEGRITY */ 1913 * after FINGERPRINT. Note that non-FINGERPRINT is 1914 * allowed to appear after M-I 1915 */ 1884 1916 if (p_response) { 1885 1917 pj_stun_msg_create_response(pool, msg, … … 1887 1919 NULL, p_response); 1888 1920 } 1889 return has_fingerprint ? PJNATH_ESTUNFINGERPOS : 1890 PJNATH_ESTUNMSGINTPOS; 1921 return PJNATH_ESTUNFINGERPOS; 1891 1922 } 1892 1923 } … … 2115 2146 } 2116 2147 2117 /* We MUST update the message length in the header NOW before 2118 * calculating MESSAGE-INTEGRITY and FINGERPRINT. 2119 * Note that length is not including the 20 bytes header. 2148 /* If MESSAGE-INTEGRITY is present, include the M-I attribute 2149 * in message length before calculating M-I 2120 2150 */ 2121 if (amsgint && afingerprint) { 2122 body_len = (pj_uint16_t)((buf - start) - 20 + 24 + 8); 2123 } else if (amsgint) { 2151 if (amsgint) { 2124 2152 body_len = (pj_uint16_t)((buf - start) - 20 + 24); 2125 } else if (afingerprint) {2126 body_len = (pj_uint16_t)((buf - start) - 20 + 8);2127 2153 } else { 2128 2154 body_len = (pj_uint16_t)((buf - start) - 20); … … 2162 2188 pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key->ptr, key->slen); 2163 2189 pj_hmac_sha1_update(&ctx, (pj_uint8_t*)start, buf-start); 2164 if ((buf-start) & 0x3F) { 2165 pj_uint8_t zeroes[64]; 2166 pj_bzero(zeroes, sizeof(zeroes)); 2167 pj_hmac_sha1_update(&ctx, zeroes, 64-((buf-start) & 0x3F)); 2168 } 2190 // These are obsoleted in rfc3489bis-08 2191 //if ((buf-start) & 0x3F) { 2192 // pj_uint8_t zeroes[64]; 2193 // pj_bzero(zeroes, sizeof(zeroes)); 2194 // pj_hmac_sha1_update(&ctx, zeroes, 64-((buf-start) & 0x3F)); 2195 //} 2169 2196 pj_hmac_sha1_final(&ctx, amsgint->hmac); 2170 2197 … … 2181 2208 /* Calculate FINGERPRINT if present */ 2182 2209 if (afingerprint != NULL) { 2210 /* Update message length */ 2211 PUTVAL16H(start, 2, 2212 (pj_uint16_t)(GETVAL16H(start, 2)+8)); 2213 2183 2214 afingerprint->value = pj_crc32_calc(start, buf-start); 2184 2215 afingerprint->value ^= STUN_XOR_FINGERPRINT; -
pjproject/trunk/pjnath/src/pjnath/stun_msg_dump.c
r1405 r1439 193 193 } 194 194 break; 195 case PJ_STUN_ATTR_ICE_CONTROLLED: 196 case PJ_STUN_ATTR_ICE_CONTROLLING: 197 { 198 const pj_stun_uint64_attr *attr; 199 pj_uint8_t data[8]; 200 int i; 201 202 attr = (const pj_stun_uint64_attr*) ahdr; 203 204 for (i=0; i<8; ++i) 205 data[i] = ((const pj_uint8_t*)&attr->value)[7-i]; 206 207 len = print_binary(p, end-p, data, 8); 208 APPLY(); 209 } 210 break; 195 211 case PJ_STUN_ATTR_USE_CANDIDATE: 196 212 default:
Note: See TracChangeset
for help on using the changeset viewer.