Changeset 1439


Ignore:
Timestamp:
Sep 18, 2007 7:33:33 PM (17 years ago)
Author:
bennylp
Message:

Ticket #374: Update STUN specification from rfc3489bis-06 to rfc3489bis-10

Location:
pjproject/trunk/pjnath
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/include/pjnath/config.h

    r1275 r1439  
    5050 
    5151/* ************************************************************************** 
    52  * STUN CLIENT CONFIGURATION 
     52 * STUN CONFIGURATION 
    5353 */ 
    5454 
     
    8181 * after this time, the STUN transaction will be considered to have failed. 
    8282 * 
    83  * The default value is 1600 miliseconds (as per RFC 3489-bis). 
     83 * The default value is 16x RTO (as per RFC 3489-bis). 
    8484 */ 
    8585#ifndef PJ_STUN_TIMEOUT_VALUE 
    86 #   define PJ_STUN_TIMEOUT_VALUE                    1600 
     86#   define PJ_STUN_TIMEOUT_VALUE                    (16 * PJ_STUN_RTO_VALUE) 
    8787#endif 
    8888 
     
    121121#define PJ_STUN_PORT                                3478 
    122122 
     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 
    123132 
    124133 
  • pjproject/trunk/pjnath/include/pjnath/stun_msg.h

    r1417 r1439  
    281281    PJ_STUN_ATTR_CHANGED_ADDR       = 0x0005,/**< CHANGED-ADDRESS (deprecatd)*/ 
    282282    PJ_STUN_ATTR_USERNAME           = 0x0006,/**< USERNAME attribute.       */ 
    283     PJ_STUN_ATTR_PASSWORD           = 0x0007,/**< PASSWORD attribute.       */ 
     283    PJ_STUN_ATTR_PASSWORD           = 0x0007,/**< was PASSWORD attribute.   */ 
    284284    PJ_STUN_ATTR_MESSAGE_INTEGRITY  = 0x0008,/**< MESSAGE-INTEGRITY.        */ 
    285285    PJ_STUN_ATTR_ERROR_CODE         = 0x0009,/**< ERROR-CODE.               */ 
     
    330330    PJ_STUN_SC_UNAUTHORIZED             = 401,  /**< Unauthorized           */ 
    331331    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 
    340343    PJ_STUN_SC_STALE_NONCE              = 438,  /**< Stale Nonce            */ 
    341344    PJ_STUN_SC_TRANSITIONING            = 439,  /**< Transitioning.         */ 
     
    10921095 
    10931096/** 
     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 */ 
     1102PJ_DECL(int) pj_stun_set_padding_char(int chr); 
     1103 
     1104 
     1105/** 
    10941106 * Create a generic STUN message. 
    10951107 * 
  • pjproject/trunk/pjnath/include/pjnath/types.h

    r1126 r1439  
    143143 * References for STUN: 
    144144 * 
    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 Traversal  
     145 *  - <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  
    147147 *     Utilities for (NAT) (STUN), 
    148148 *  - <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-behave-turn-03.txt"> 
  • pjproject/trunk/pjnath/src/pjnath-test/stun.c

    r1093 r1439  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
     19#include "test.h" 
     20 
     21#define THIS_FILE   "stun.c" 
     22 
     23static pj_stun_msg* create1(pj_pool_t*); 
     24static int verify1(pj_stun_msg*); 
     25static int verify2(pj_stun_msg*); 
     26static int verify5(pj_stun_msg*); 
     27 
     28static 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 
     220static 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 
     227static const pj_str_t USERNAME = {"user", 4}; 
     228static const pj_str_t PASSWORD = {"password", 8}; 
    19229 
    20230static int decode_test(void) 
    21231{ 
    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 
     299on_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 */ 
     307static 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 */ 
     327static 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    } 
    51365 
    52366    return 0; 
    53367} 
     368 
     369/* Attribute count should be zero since unknown attribute is not parsed */ 
     370static 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 */ 
     381static 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 
    54404 
    55405static int decode_verify(void) 
     
    108458} 
    109459 
     460typedef struct test_vector test_vector; 
     461 
     462static pj_stun_msg* create_msgint1(pj_pool_t *pool, test_vector *v); 
     463static pj_stun_msg* create_msgint2(pj_pool_t *pool, test_vector *v); 
     464 
     465enum 
     466{ 
     467    USE_MESSAGE_INTEGRITY   = 1, 
     468    USE_FINGERPRINT         = 2 
     469}; 
     470 
     471struct 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 
     521static 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 
     549static 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 
     560static 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 
     686on_return: 
     687    pj_pool_release(pool); 
     688    return rc; 
     689} 
     690 
     691static 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 
     716static 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 
    110739 
    111740int stun_test(void) 
    112741{ 
    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 
     762on_return: 
     763    pj_stun_set_padding_char(pad); 
     764    return rc; 
     765} 
     766 
  • pjproject/trunk/pjnath/src/pjnath-test/test.c

    r1288 r1439  
    6767    pjnath_init(); 
    6868 
     69#if INCLUDE_STUN_TEST 
     70    DO_TEST(stun_test()); 
     71#endif 
     72 
    6973#if INCLUDE_ICE_TEST 
    7074    DO_TEST(ice_test()); 
  • pjproject/trunk/pjnath/src/pjnath-test/test.h

    r1093 r1439  
    2121#include <pjnath.h> 
    2222 
     23#define INCLUDE_STUN_TEST           1 
    2324#define INCLUDE_ICE_TEST            1 
    2425 
     26extern int stun_test(void); 
    2527extern int ice_test(void); 
    2628extern int test_main(void); 
  • pjproject/trunk/pjnath/src/pjnath/ice_session.c

    r1435 r1439  
    490490        /* Verify username */ 
    491491        if (pj_strcmp(username, &ice->tx_uname) != 0) 
    492             return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_USERNAME); 
     492            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 
    493493        *data_type = 0; 
    494494        *data = ice->tx_pass; 
     
    508508        pos = (const char*)pj_memchr(username->ptr, ':', username->slen); 
    509509        if (pos == NULL) 
    510             return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_USERNAME); 
     510            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 
    511511 
    512512        ufrag.ptr = (char*)username->ptr; 
     
    514514 
    515515        if (pj_strcmp(&ufrag, &ice->rx_ufrag) != 0) 
    516             return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_USERNAME); 
     516            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 
    517517 
    518518        *data_type = 0; 
  • pjproject/trunk/pjnath/src/pjnath/stun_auth.c

    r1374 r1439  
    6060 
    6161 
     62PJ_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 
    6269/* Send 401 response */ 
    6370static pj_status_t create_challenge(pj_pool_t *pool, 
    6471                                    const pj_stun_msg *msg, 
    6572                                    int err_code, 
    66                                     const pj_str_t *err_msg, 
     73                                    const char *errstr, 
    6774                                    const pj_str_t *realm, 
    6875                                    const pj_str_t *nonce, 
     
    7178    pj_stun_msg *response; 
    7279    pj_str_t tmp_nonce; 
     80    pj_str_t err_msg; 
    7381    pj_status_t rc; 
    7482 
    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); 
    7786    if (rc != PJ_SUCCESS) 
    7887        return rc; 
     
    117126    pj_str_t realm, nonce, password; 
    118127    const pj_stun_msgint_attr *amsgi; 
    119     unsigned amsgi_pos; 
     128    unsigned i, amsgi_pos; 
     129    pj_bool_t has_attr_beyond_mi; 
    120130    const pj_stun_username_attr *auser; 
    121131    pj_bool_t username_ok; 
     
    139149        p_response = NULL; 
    140150 
    141     /* Get realm and nonce */ 
     151    /* Get realm and nonce from credential */ 
    142152    realm.slen = nonce.slen = 0; 
    143153    if (cred->type == PJ_STUN_AUTH_CRED_STATIC) { 
     
    154164    } 
    155165 
    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 
    159181    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; 
    160189        if (p_response) { 
    161             create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, NULL, 
     190            create_challenge(pool, msg, code, NULL, 
    162191                             &realm, &nonce, p_response); 
    163192        } 
    164         return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE); 
     193        return PJ_STATUS_FROM_STUN_CODE(code); 
    165194    } 
    166195 
     
    169198            pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0); 
    170199    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; 
    171205        if (p_response) { 
    172             create_challenge(pool, msg, PJ_STUN_SC_MISSING_USERNAME, NULL, 
     206            create_challenge(pool, msg, code, "Missing USERNAME", 
    173207                             &realm, &nonce, p_response); 
    174208        } 
    175         return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_USERNAME); 
     209        return PJ_STATUS_FROM_STUN_CODE(code); 
    176210    } 
    177211 
     
    201235    if (!username_ok) { 
    202236        /* Username mismatch */ 
     237        /* According to rfc3489bis-10 Sec 10.1.2/10.2.2, we should  
     238         * return 401  
     239         */ 
    203240        if (p_response) { 
    204             create_challenge(pool, msg, PJ_STUN_SC_UNKNOWN_USERNAME, NULL, 
     241            create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, NULL, 
    205242                             &realm, &nonce, p_response); 
    206243        } 
    207         return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_USERNAME); 
     244        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 
    208245    } 
    209246 
     
    217254        /* Long term credential is required and REALM is not present */ 
    218255        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", 
    220258                             &realm, &nonce, p_response); 
    221259        } 
    222         return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_REALM); 
     260        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST); 
    223261 
    224262    } else if (realm.slen != 0 && arealm != NULL) { 
     
    228266        if (anonce == NULL && nonce.slen) { 
    229267            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); 
    232270            } 
    233             return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_NONCE); 
     271            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST); 
    234272        } 
    235273 
     
    238276            /* REALM doesn't match */ 
    239277            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); 
    242280            } 
    243             return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_REALM); 
     281            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 
    244282        } 
    245283 
     
    261299        if (nonce.slen != 0) { 
    262300            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); 
    265303            } 
    266             return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_NONCE); 
     304            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 
    267305        } 
    268306    } 
     
    295333                                 NULL, &realm, &nonce, p_response); 
    296334            } 
    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        } 
    321337    } 
    322338 
     
    324340    pj_stun_create_key(pool, &key, &realm, &auser->value, &password); 
    325341 
    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. 
    328348     */ 
    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    //} 
    336366    pj_hmac_sha1_final(&ctx, digest); 
     367 
    337368 
    338369    /* Compare HMACs */ 
    339370    if (pj_memcmp(amsgi->hmac, digest, 20)) { 
    340371        /* HMAC value mismatch */ 
     372        /* According to rfc3489bis-10 Sec 10.1.2 we should return 401 */ 
    341373        if (p_response) { 
    342             create_challenge(pool, msg, PJ_STUN_SC_INTEGRITY_CHECK_FAILURE, 
     374            create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, 
    343375                             NULL, &realm, &nonce, p_response); 
    344376        } 
    345         return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE); 
     377        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNAUTHORIZED); 
    346378    } 
    347379 
     
    382414    case PJ_STUN_SC_BAD_REQUEST:            /* 400 (Bad Request)            */ 
    383415    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) */ 
    389421        return PJ_FALSE; 
    390422    default: 
     
    401433{ 
    402434    const pj_stun_msgint_attr *amsgi; 
    403     unsigned amsgi_pos; 
     435    unsigned i, amsgi_pos; 
     436    pj_bool_t has_attr_beyond_mi; 
    404437    pj_hmac_sha1_context ctx; 
    405438    pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE]; 
     
    411444            pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0); 
    412445    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); 
    414447    } 
    415448 
     
    420453    } 
    421454 
    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); 
    426486    } 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    //} 
    458498    pj_hmac_sha1_final(&ctx, digest); 
    459499 
     
    461501    if (pj_memcmp(amsgi->hmac, digest, 20)) { 
    462502        /* 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); 
    464504    } 
    465505 
  • pjproject/trunk/pjnath/src/pjnath/stun_msg.c

    r1410 r1439  
    3232#define STUN_XOR_FINGERPRINT    0x5354554eL 
    3333 
     34static int padding_char; 
     35 
    3436static const char *stun_method_names[] =  
    3537{ 
     
    5557    { PJ_STUN_SC_UNAUTHORIZED,              "Unauthorized"}, 
    5658    { 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"}, 
    6567    { PJ_STUN_SC_STALE_NONCE,               "Stale Nonce"}, 
    6668    { PJ_STUN_SC_TRANSITIONING,             "Active Destination Already Set"}, 
     
    569571 
    570572 
     573/* 
     574 * Set padding character. 
     575 */ 
     576PJ_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 
    571584////////////////////////////////////////////////////////////////////////////// 
    572585 
     
    900913    /* Copy the string */ 
    901914    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    } 
    902923 
    903924    /* Done */ 
     
    13791400     * attributes MUST be repeated in the list. 
    13801401     */ 
     1402    /* No longer necessary 
    13811403    if ((attr_cnt & 0x01)) { 
    13821404        attr->attrs[attr_cnt] = attr_array[attr_cnt-1]; 
    13831405    } 
    1384  
    1385     *p_attr = NULL; 
     1406    */ 
     1407 
     1408    *p_attr = attr; 
    13861409 
    13871410    return PJ_SUCCESS; 
     
    16341657        ((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len)) 
    16351658    { 
     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) { 
    16361666        return PJNATH_EINSTUNMSGLEN; 
    16371667    } 
     
    18791909                has_fingerprint = PJ_TRUE; 
    18801910            } else { 
    1881                 if (has_msg_int || has_fingerprint) { 
     1911                if (has_fingerprint) { 
    18821912                    /* 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                     */ 
    18841916                    if (p_response) { 
    18851917                        pj_stun_msg_create_response(pool, msg, 
     
    18871919                                                    NULL, p_response); 
    18881920                    } 
    1889                     return has_fingerprint ? PJNATH_ESTUNFINGERPOS : 
    1890                                              PJNATH_ESTUNMSGINTPOS; 
     1921                    return PJNATH_ESTUNFINGERPOS; 
    18911922                } 
    18921923            } 
     
    21152146    } 
    21162147 
    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 
    21202150     */ 
    2121     if (amsgint && afingerprint) { 
    2122         body_len = (pj_uint16_t)((buf - start) - 20 + 24 + 8); 
    2123     } else if (amsgint) { 
     2151    if (amsgint) { 
    21242152        body_len = (pj_uint16_t)((buf - start) - 20 + 24); 
    2125     } else if (afingerprint) { 
    2126         body_len = (pj_uint16_t)((buf - start) - 20 + 8); 
    21272153    } else { 
    21282154        body_len = (pj_uint16_t)((buf - start) - 20); 
     
    21622188        pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key->ptr, key->slen); 
    21632189        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        //} 
    21692196        pj_hmac_sha1_final(&ctx, amsgint->hmac); 
    21702197 
     
    21812208    /* Calculate FINGERPRINT if present */ 
    21822209    if (afingerprint != NULL) { 
     2210        /* Update message length */ 
     2211        PUTVAL16H(start, 2,  
     2212                 (pj_uint16_t)(GETVAL16H(start, 2)+8)); 
     2213 
    21832214        afingerprint->value = pj_crc32_calc(start, buf-start); 
    21842215        afingerprint->value ^= STUN_XOR_FINGERPRINT; 
  • pjproject/trunk/pjnath/src/pjnath/stun_msg_dump.c

    r1405 r1439  
    193193        } 
    194194        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; 
    195211    case PJ_STUN_ATTR_USE_CANDIDATE: 
    196212    default: 
Note: See TracChangeset for help on using the changeset viewer.