Ignore:
Timestamp:
Feb 26, 2007 2:33:14 AM (14 years ago)
Author:
bennylp
Message:

Added CRC32 code to pjlib-util, and implemented STUN FINGERPRINT and MESSAGE-INTEGRITY

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c

    r1001 r1002  
    1818 */ 
    1919#include <pjlib-util/stun_msg.h> 
     20#include <pjlib-util/crc32.h> 
    2021#include <pjlib-util/errno.h> 
     22#include <pjlib-util/hmac_sha1.h> 
     23#include <pjlib-util/md5.h> 
    2124#include <pj/assert.h> 
    2225#include <pj/log.h> 
     
    2629#include <pj/string.h> 
    2730 
    28 #define THIS_FILE   "stun_msg.c" 
    29  
     31#define THIS_FILE               "stun_msg.c" 
     32#define STUN_XOR_FINGERPRINT    0x5354554eL 
    3033 
    3134static const char *stun_method_names[] =  
     
    548551 
    549552 
     553/* 
     554 * Create and add generic STUN IP address attribute to a STUN message. 
     555 */ 
     556PJ_DEF(pj_status_t)  
     557pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool, 
     558                                     pj_stun_msg *msg, 
     559                                     int attr_type,  
     560                                     pj_bool_t xor_ed, 
     561                                     unsigned addr_len, 
     562                                     const pj_sockaddr_t *addr) 
     563{ 
     564    pj_stun_generic_ip_addr_attr *attr; 
     565    pj_status_t status; 
     566 
     567    status = pj_stun_generic_ip_addr_attr_create(pool, attr_type, xor_ed, 
     568                                                 addr_len, addr, &attr); 
     569    if (status != PJ_SUCCESS) 
     570        return status; 
     571 
     572    return pj_stun_msg_add_attr(msg, &attr->hdr); 
     573} 
     574 
    550575static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool,  
    551576                                               const pj_uint8_t *buf,  
     
    659684 
    660685 
     686/* 
     687 * Create and add STUN generic string attribute to the message. 
     688 */ 
     689PJ_DEF(pj_status_t)  
     690pj_stun_msg_add_generic_string_attr(pj_pool_t *pool, 
     691                                    pj_stun_msg *msg, 
     692                                    int attr_type, 
     693                                    const pj_str_t *value) 
     694{ 
     695    pj_stun_generic_string_attr *attr; 
     696    pj_status_t status; 
     697 
     698    status = pj_stun_generic_string_attr_create(pool, attr_type, value,  
     699                                                &attr); 
     700    if (status != PJ_SUCCESS) 
     701        return status; 
     702 
     703    return pj_stun_msg_add_attr(msg, &attr->hdr); 
     704} 
     705 
     706 
    661707static pj_status_t decode_generic_string_attr(pj_pool_t *pool,  
    662708                                              const pj_uint8_t *buf,  
     
    828874} 
    829875 
     876/* Create and add STUN generic 32bit value attribute to the message. */ 
     877PJ_DEF(pj_status_t)  
     878pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool, 
     879                                  pj_stun_msg *msg, 
     880                                  int attr_type, 
     881                                  pj_uint32_t value) 
     882{ 
     883    pj_stun_generic_uint_attr *attr; 
     884    pj_status_t status; 
     885 
     886    status = pj_stun_generic_uint_attr_create(pool, attr_type, value, &attr); 
     887    if (status != PJ_SUCCESS) 
     888        return status; 
     889 
     890    return pj_stun_msg_add_attr(msg, &attr->hdr); 
     891} 
    830892 
    831893static pj_status_t decode_generic_uint_attr(pj_pool_t *pool,  
     
    10881150pj_stun_unknown_attr_create(pj_pool_t *pool, 
    10891151                            unsigned attr_cnt, 
    1090                             pj_uint16_t attr_array[], 
     1152                            const pj_uint16_t attr_array[], 
    10911153                            pj_stun_unknown_attr **p_attr) 
    10921154{ 
     
    11171179 
    11181180 
     1181/* Create and add STUN UNKNOWN-ATTRIBUTES attribute to the message. */ 
     1182PJ_DEF(pj_status_t)  
     1183pj_stun_msg_add_unknown_attr(pj_pool_t *pool, 
     1184                             pj_stun_msg *msg, 
     1185                             unsigned attr_cnt, 
     1186                             const pj_uint16_t attr_types[]) 
     1187{ 
     1188    pj_stun_unknown_attr *attr; 
     1189    pj_status_t status; 
     1190 
     1191    status = pj_stun_unknown_attr_create(pool, attr_cnt, attr_types, &attr); 
     1192    if (status != PJ_SUCCESS) 
     1193        return status; 
     1194 
     1195    return pj_stun_msg_add_attr(msg, &attr->hdr); 
     1196} 
     1197 
    11191198static pj_status_t decode_unknown_attr(pj_pool_t *pool,  
    11201199                                       const pj_uint8_t *buf,  
     
    11941273pj_stun_binary_attr_create(pj_pool_t *pool, 
    11951274                           int attr_type, 
     1275                           const pj_uint8_t *data, 
     1276                           unsigned length, 
    11961277                           pj_stun_binary_attr **p_attr) 
    11971278{ 
     
    12031284    INIT_ATTR(attr, attr_type, sizeof(pj_stun_binary_attr)); 
    12041285 
     1286    if (data && length) { 
     1287        attr->length = length; 
     1288        attr->data = pj_pool_alloc(pool, length); 
     1289        pj_memcpy(attr->data, data, length); 
     1290    } 
     1291 
    12051292    *p_attr = attr; 
    12061293 
    12071294    return PJ_SUCCESS; 
     1295} 
     1296 
     1297 
     1298/* Create and add binary attr. */ 
     1299PJ_DEF(pj_status_t) 
     1300pj_stun_msg_add_binary_attr(pj_pool_t *pool, 
     1301                            pj_stun_msg *msg, 
     1302                            int attr_type, 
     1303                            const pj_uint8_t *data, 
     1304                            unsigned length) 
     1305{ 
     1306    pj_stun_binary_attr *attr; 
     1307    pj_status_t status; 
     1308 
     1309    status = pj_stun_binary_attr_create(pool, attr_type, 
     1310                                        data, length, &attr); 
     1311    if (status != PJ_SUCCESS) 
     1312        return status; 
     1313 
     1314    return pj_stun_msg_add_attr(msg, &attr->hdr); 
    12081315} 
    12091316 
     
    13251432 
    13261433 
     1434PJ_INLINE(pj_uint16_t) GET_VAL16(const pj_uint8_t *pdu, unsigned pos) 
     1435{ 
     1436    pj_uint16_t val = (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]); 
     1437    return pj_ntohs(val); 
     1438} 
     1439 
     1440PJ_INLINE(pj_uint32_t) GET_VAL32(const pj_uint8_t *pdu, unsigned pos) 
     1441{ 
     1442    pj_uint32_t val = (pdu[pos+0] << 24) + 
     1443                      (pdu[pos+1] << 16) + 
     1444                      (pdu[pos+2] <<  8) + 
     1445                      (pdu[pos+3]); 
     1446    return pj_ntohl(val); 
     1447} 
     1448 
     1449 
    13271450/* 
    13281451 * Check that the PDU is potentially a valid STUN message. 
    13291452 */ 
    1330 PJ_DEF(pj_status_t) pj_stun_msg_check(const void *pdu, unsigned pdu_len, 
     1453PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len, 
    13311454                                      unsigned options) 
    13321455{ 
    1333     pj_stun_msg_hdr *hdr; 
     1456    unsigned msg_len; 
    13341457 
    13351458    PJ_ASSERT_RETURN(pdu, PJ_EINVAL); 
     
    13381461        return PJLIB_UTIL_ESTUNINMSGLEN; 
    13391462 
    1340     PJ_UNUSED_ARG(options); 
    1341  
    1342     hdr = (pj_stun_msg_hdr*) pdu; 
    1343  
    13441463    /* First byte of STUN message is always 0x00 or 0x01. */ 
    1345     if ((*(const char*)pdu) != 0x00 && (*(const char*)pdu) != 0x01) 
     1464    if (*pdu != 0x00 && *pdu != 0x01) 
    13461465        return PJLIB_UTIL_ESTUNINMSGTYPE; 
    13471466 
     
    13491468     * a STUN message. 
    13501469     */ 
    1351     if (pj_ntohl(hdr->magic) == PJ_STUN_MAGIC) 
    1352         return PJ_SUCCESS; 
     1470    if (GET_VAL32(pdu, 4) != PJ_STUN_MAGIC) 
     1471        return PJLIB_UTIL_ESTUNNOTMAGIC; 
    13531472 
    13541473    /* Check the PDU length */ 
    1355     if (pj_ntohs(hdr->length) > pdu_len) 
     1474    msg_len = GET_VAL16(pdu, 2); 
     1475    if ((msg_len > pdu_len) ||  
     1476        ((options & PJ_STUN_IS_DATAGRAM) && msg_len != pdu_len)) 
     1477    { 
    13561478        return PJLIB_UTIL_ESTUNINMSGLEN; 
     1479    } 
     1480 
     1481    /* Check if FINGERPRINT attribute is present */ 
     1482    if (GET_VAL16(pdu, msg_len + 20) == PJ_STUN_ATTR_FINGERPRINT) { 
     1483        pj_uint16_t attr_len = GET_VAL16(pdu, msg_len + 22); 
     1484        pj_uint32_t fingerprint = GET_VAL32(pdu, msg_len + 24); 
     1485        pj_uint32_t crc; 
     1486 
     1487        if (attr_len != 4) 
     1488            return PJLIB_UTIL_ESTUNINATTRLEN; 
     1489 
     1490        crc = pj_crc32_calc(pdu, msg_len + 20); 
     1491        crc ^= STUN_XOR_FINGERPRINT; 
     1492 
     1493        if (crc != fingerprint) 
     1494            return PJLIB_UTIL_ESTUNFINGERPRINT; 
     1495    } 
    13571496 
    13581497    /* Could be a STUN message */ 
     1498    return PJ_SUCCESS; 
     1499} 
     1500 
     1501 
     1502/* Create error response */ 
     1503PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool, 
     1504                                                const pj_stun_msg *req_msg, 
     1505                                                unsigned err_code, 
     1506                                                const pj_str_t *err_msg, 
     1507                                                pj_stun_msg **p_response) 
     1508{ 
     1509    unsigned msg_type = req_msg->hdr.type; 
     1510    pj_stun_msg *response; 
     1511    pj_stun_error_code_attr *err_attr; 
     1512    pj_status_t status; 
     1513 
     1514    PJ_ASSERT_RETURN(pool && p_response, PJ_EINVAL); 
     1515 
     1516    PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(msg_type),  
     1517                     PJLIB_UTIL_ESTUNINMSGTYPE); 
     1518 
     1519    /* Create response or error response */ 
     1520    if (err_code) 
     1521        msg_type |= PJ_STUN_ERROR_RESPONSE_BIT; 
     1522    else 
     1523        msg_type |= PJ_STUN_RESPONSE_BIT; 
     1524 
     1525    status = pj_stun_msg_create(pool, msg_type, req_msg->hdr.magic,  
     1526                                req_msg->hdr.tsx_id, &response); 
     1527    if (status != PJ_SUCCESS) { 
     1528        return status; 
     1529    } 
     1530 
     1531    /* Add error code attribute */ 
     1532    if (err_code) { 
     1533        status = pj_stun_error_code_attr_create(pool, err_code, err_msg, 
     1534                                                &err_attr); 
     1535        if (status != PJ_SUCCESS) { 
     1536            return status; 
     1537        } 
     1538 
     1539        pj_stun_msg_add_attr(response, &err_attr->hdr); 
     1540    } 
     1541 
     1542    *p_response = response; 
    13591543    return PJ_SUCCESS; 
    13601544} 
     
    13701554                                       pj_stun_msg **p_msg, 
    13711555                                       unsigned *p_parsed_len, 
    1372                                        unsigned *p_err_code, 
    1373                                        unsigned *p_uattr_cnt, 
    1374                                        pj_uint16_t uattr[]) 
     1556                                       pj_stun_msg **p_response) 
    13751557{ 
    13761558     
     
    13851567    PJ_ASSERT_RETURN(sizeof(pj_stun_msg_hdr) == 20, PJ_EBUG); 
    13861568 
    1387     /* Application should have checked that this is a valid STUN msg */ 
    1388     PJ_ASSERT_RETURN((status=pj_stun_msg_check(pdu, pdu_len, options)) 
    1389                         == PJ_SUCCESS, status); 
     1569    if (p_parsed_len) 
     1570        *p_parsed_len = 0; 
     1571    if (p_response) 
     1572        *p_response = NULL; 
     1573 
     1574    /* Check if this is a STUN message, if necessary */ 
     1575    if (options & PJ_STUN_CHECK_PACKET) { 
     1576        status = pj_stun_msg_check(pdu, pdu_len, options); 
     1577        if (status != PJ_SUCCESS) 
     1578            return status; 
     1579    } 
    13901580 
    13911581    /* Create the message, copy the header, and convert to host byte order */ 
     
    13991589    pdu_len -= sizeof(pj_stun_msg_hdr); 
    14001590 
    1401     if (p_err_code) 
    1402         *p_err_code = 0; 
     1591    /* No need to create response if this is not a request */ 
     1592    if (!PJ_STUN_IS_REQUEST(msg->hdr.type)) 
     1593        p_response = NULL; 
    14031594 
    14041595    /* Parse attributes */ 
     
    14161607 
    14171608        /* Check length */ 
    1418         if (pdu_len < attr_val_len) 
     1609        if (pdu_len < attr_val_len) { 
     1610            pj_str_t err_msg; 
     1611            char err_msg_buf[80]; 
     1612 
     1613            err_msg.ptr = err_msg_buf; 
     1614            err_msg.slen = pj_ansi_snprintf(err_msg_buf, sizeof(err_msg_buf), 
     1615                                            "Attribute %s has invalid length", 
     1616                                            pj_stun_get_attr_name(attr_type)); 
     1617 
     1618            PJ_LOG(4,(THIS_FILE, "Error decoding message: %.*s", 
     1619                      (int)err_msg.slen, err_msg.ptr)); 
     1620 
     1621            if (p_response) { 
     1622                pj_stun_msg_create_response(pool, msg,  
     1623                                            PJ_STUN_STATUS_BAD_REQUEST,  
     1624                                            &err_msg, p_response); 
     1625            } 
    14191626            return PJLIB_UTIL_ESTUNINATTRLEN; 
     1627        } 
    14201628 
    14211629        /* Get the attribute descriptor */ 
     
    14271635            PJ_LOG(4,(THIS_FILE, "Unrecognized attribute type %d",  
    14281636                      attr_type)); 
    1429  
    1430             /* Put to unrecognized attribute array */ 
    1431             if (p_uattr_cnt && uattr && uattr_cnt < *p_uattr_cnt) { 
    1432                 uattr[uattr_cnt++] = (pj_uint16_t)attr_type; 
    1433             } 
    14341637 
    14351638            /* Is this a fatal condition? */ 
     
    14381641                 * if we don't understand the attribute. 
    14391642                 */ 
    1440                 if (p_err_code && *p_err_code == 0) 
    1441                     *p_err_code = PJ_STUN_STATUS_UNKNOWN_ATTRIBUTE; 
     1643                if (p_response) { 
     1644                    unsigned err_code = PJ_STUN_STATUS_UNKNOWN_ATTRIBUTE; 
     1645 
     1646                    status = pj_stun_msg_create_response(pool, msg, 
     1647                                                         err_code, NULL,  
     1648                                                         p_response); 
     1649                    if (status==PJ_SUCCESS) { 
     1650                        pj_uint16_t d = (pj_uint16_t)attr_type; 
     1651                        pj_stun_msg_add_unknown_attr(pool, *p_response, 1, &d); 
     1652                    } 
     1653                } 
    14421654 
    14431655                return PJLIB_UTIL_ESTUNUNKNOWNATTR; 
     
    14461658        } else { 
    14471659            void *attr; 
     1660            char err_msg1[PJ_ERR_MSG_SIZE], 
     1661                 err_msg2[PJ_ERR_MSG_SIZE]; 
    14481662 
    14491663            /* Parse the attribute */ 
     
    14511665 
    14521666            if (status != PJ_SUCCESS) { 
     1667                pj_strerror(status, err_msg1, sizeof(err_msg1)); 
     1668 
     1669                if (p_response) { 
     1670                    pj_str_t e; 
     1671 
     1672                    e.ptr = err_msg2; 
     1673                    e.slen= pj_ansi_snprintf(err_msg2, sizeof(err_msg2), 
     1674                                             "%s in %s", 
     1675                                             err_msg1, 
     1676                                             pj_stun_get_attr_name(attr_type)); 
     1677 
     1678                    pj_stun_msg_create_response(pool, msg, 
     1679                                                PJ_STUN_STATUS_BAD_REQUEST, 
     1680                                                &e, p_response); 
     1681                } 
     1682 
    14531683                PJ_LOG(4,(THIS_FILE,  
    1454                           "Error parsing STUN attribute type %d: status=%d", 
    1455                           attr_type, status)); 
     1684                          "Error parsing STUN attribute %s: %s", 
     1685                          pj_stun_get_attr_name(attr_type),  
     1686                          err_msg1)); 
     1687 
    14561688                return status; 
    14571689            } 
    14581690             
    14591691            /* Make sure we have rooms for the new attribute */ 
    1460             if (msg->attr_count >= PJ_STUN_MAX_ATTR) 
     1692            if (msg->attr_count >= PJ_STUN_MAX_ATTR) { 
     1693                if (p_response) { 
     1694                    pj_str_t e; 
     1695 
     1696                    e = pj_str("Too many attributes"); 
     1697                    pj_stun_msg_create_response(pool, msg, 
     1698                                                PJ_STUN_STATUS_BAD_REQUEST, 
     1699                                                &e, p_response); 
     1700                } 
    14611701                return PJLIB_UTIL_ESTUNTOOMANYATTR; 
     1702            } 
    14621703 
    14631704            /* Add the attribute */ 
     
    14701711 
    14711712    *p_msg = msg; 
    1472  
    1473     if (p_uattr_cnt) 
    1474         *p_uattr_cnt = uattr_cnt; 
    14751713 
    14761714    if (p_parsed_len) 
     
    14951733    pj_stun_username_attr *auname = NULL; 
    14961734    pj_stun_msg_integrity_attr *amsg_integrity = NULL; 
    1497     unsigned i; 
     1735    pj_stun_fingerprint_attr *afingerprint = NULL; 
     1736    unsigned printed; 
     1737    pj_status_t status; 
     1738    unsigned i, length; 
     1739 
    14981740 
    14991741    PJ_ASSERT_RETURN(msg && buf && buf_size, PJ_EINVAL); 
     
    15201762        const struct attr_desc *adesc; 
    15211763        const pj_stun_attr_hdr *attr_hdr; 
    1522         unsigned printed; 
    1523         pj_status_t status; 
    15241764 
    15251765        attr_hdr = msg->attr[i]; 
     
    15351775            pj_assert(auname == NULL); 
    15361776            auname = (pj_stun_username_attr*) attr_hdr; 
     1777 
    15371778        } else if (attr_hdr->type == PJ_STUN_ATTR_REALM) { 
    15381779            pj_assert(arealm == NULL); 
    15391780            arealm = (pj_stun_realm_attr*) attr_hdr; 
     1781 
     1782        } else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) { 
     1783            afingerprint = (pj_stun_fingerprint_attr*) attr_hdr; 
     1784            break; 
    15401785        } 
    15411786 
     
    15511796    } 
    15521797 
     1798    /* Calculate message integrity, if present */ 
    15531799    if (amsg_integrity != NULL) { 
    1554         PJ_TODO(IMPLEMENT_MSG_INTEGRITY); 
    1555     } 
    1556  
     1800 
     1801        pj_uint8_t md5_key_buf[16]; 
     1802        pj_str_t key; 
     1803 
     1804        /* MESSAGE-INTEGRITY must be the last attribute in the message, or 
     1805         * the last attribute before FINGERPRINT. 
     1806         */ 
     1807        if (i < msg->attr_count-2) { 
     1808            /* Should not happen for message generated by us */ 
     1809            pj_assert(PJ_FALSE); 
     1810            return PJLIB_UTIL_ESTUNMSGINT; 
     1811 
     1812        } else if (i == msg->attr_count-2)  { 
     1813            if (msg->attr[i+1]->type != PJ_STUN_ATTR_FINGERPRINT) { 
     1814                /* Should not happen for message generated by us */ 
     1815                pj_assert(PJ_FALSE); 
     1816                return PJLIB_UTIL_ESTUNMSGINT; 
     1817            } else { 
     1818                afingerprint = (pj_stun_fingerprint_attr*) msg->attr[i+1]; 
     1819            } 
     1820        } 
     1821 
     1822        /* Must have USERNAME attribute */ 
     1823        if (auname == NULL) { 
     1824            /* Should not happen for message generated by us */ 
     1825            pj_assert(PJ_FALSE); 
     1826            return PJLIB_UTIL_ESTUNNOUSERNAME; 
     1827        } 
     1828 
     1829        /* Password must be specified */ 
     1830        PJ_ASSERT_RETURN(password, PJ_EINVAL); 
     1831 
     1832        /* Get the key to sign the message */ 
     1833        if (arealm == NULL ) { 
     1834            /* For short term credential, the key is the password */ 
     1835            key = *password; 
     1836 
     1837        } else { 
     1838            /* The 16-byte key for MESSAGE-INTEGRITY HMAC is formed by taking 
     1839             * the MD5 hash of the result of concatenating the following five 
     1840             * fields: (1) The username, with any quotes and trailing nulls 
     1841             * removed, (2) A single colon, (3) The realm, with any quotes and 
     1842             * trailing nulls removed, (4) A single colon, and (5) The  
     1843             * password, with any trailing nulls removed. 
     1844             */ 
     1845            pj_md5_context ctx; 
     1846            pj_str_t s; 
     1847 
     1848            pj_md5_init(&ctx); 
     1849 
     1850#define REMOVE_QUOTE(s) if (s.slen && *s.ptr=='"') \ 
     1851                            s.ptr++, s.slen--; \ 
     1852                        if (s.slen && s.ptr[s.slen-1]=='"') \ 
     1853                            s.slen--; 
     1854 
     1855            /* Add username */ 
     1856            s = auname->value; 
     1857            REMOVE_QUOTE(s); 
     1858            pj_md5_update(&ctx, (pj_uint8_t*)s.ptr, s.slen); 
     1859 
     1860            /* Add single colon */ 
     1861            pj_md5_update(&ctx, (pj_uint8_t*)":", 1); 
     1862 
     1863            /* Add realm */ 
     1864            s = arealm->value; 
     1865            REMOVE_QUOTE(s); 
     1866            pj_md5_update(&ctx, (pj_uint8_t*)s.ptr, s.slen); 
     1867 
     1868#undef REMOVE_QUOTE 
     1869 
     1870            /* Another colon */ 
     1871            pj_md5_update(&ctx, (pj_uint8_t*)":", 1); 
     1872 
     1873            /* Add password */ 
     1874            pj_md5_update(&ctx, (pj_uint8_t*)password->ptr, password->slen); 
     1875 
     1876            /* Done */ 
     1877            pj_md5_final(&ctx, md5_key_buf); 
     1878            key.ptr = (char*) md5_key_buf; 
     1879            key.slen = 16; 
     1880        } 
     1881 
     1882        /* Calculate HMAC-SHA1 digest */ 
     1883        pj_hmac_sha1((pj_uint8_t*)buf, buf-start,  
     1884                     (pj_uint8_t*)key.ptr, key.slen, 
     1885                     amsg_integrity->hmac); 
     1886 
     1887        /* Put this attribute in the message */ 
     1888        status = encode_msg_integrity_attr(amsg_integrity, buf, buf_size,  
     1889                                           &printed); 
     1890        if (status != PJ_SUCCESS) 
     1891            return status; 
     1892 
     1893        buf += printed; 
     1894        buf_size -= printed; 
     1895    } 
     1896 
     1897    /* Calculate FINGERPRINT if present */ 
     1898    if (afingerprint != NULL) { 
     1899        afingerprint->value = pj_crc32_calc(start, buf-start); 
     1900        afingerprint->value ^= STUN_XOR_FINGERPRINT; 
     1901 
     1902        /* Put this attribute in the message */ 
     1903        status = encode_generic_uint_attr(afingerprint, buf, buf_size,  
     1904                                          &printed); 
     1905        if (status != PJ_SUCCESS) 
     1906            return status; 
     1907 
     1908        buf += printed; 
     1909        buf_size -= printed; 
     1910    } 
    15571911 
    15581912    /* Update the message length in the header.  
    15591913     * Note that length is not including the 20 bytes header. 
    15601914     */ 
    1561     hdr->length = (pj_uint16_t)((buf - start) - 20); 
    1562     hdr->length = pj_htons(hdr->length); 
     1915    length = (pj_uint16_t)((buf - start) - 20); 
     1916    /* hdr->length = pj_htons(length); */ 
     1917    *(buf+2) = (pj_uint8_t)((length >> 8) & 0x00FF); 
     1918    *(buf+3) = (pj_uint8_t)(length & 0x00FF); 
     1919 
    15631920 
    15641921    /* Done */ 
     
    15881945} 
    15891946 
     1947 
     1948/* Verify credential */ 
     1949PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_stun_msg *msg, 
     1950                                               const pj_str_t *realm, 
     1951                                               const pj_str_t *username, 
     1952                                               const pj_str_t *password, 
     1953                                               unsigned options, 
     1954                                               pj_pool_t *pool, 
     1955                                               pj_stun_msg **p_response) 
     1956{ 
     1957    const pj_stun_msg_integrity_attr *amsgi; 
     1958    const pj_stun_username_attr *auser; 
     1959    const pj_stun_realm_attr *arealm; 
     1960 
     1961    PJ_ASSERT_RETURN(msg && password, PJ_EINVAL); 
     1962    PJ_ASSERT_RETURN(options==0, PJ_EINVAL); 
     1963    PJ_UNUSED_ARG(options); 
     1964 
     1965    if (p_response) 
     1966        *p_response = NULL; 
     1967 
     1968    /* First check that MESSAGE-INTEGRITY is present */ 
     1969    amsgi = (const pj_stun_msg_integrity_attr*) 
     1970            pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0); 
     1971    if (amsgi == NULL) { 
     1972        if (pool && p_response) { 
     1973            pj_status_t rc; 
     1974 
     1975            rc = pj_stun_msg_create_response(pool, msg,  
     1976                                             PJ_STUN_STATUS_UNAUTHORIZED,  
     1977                                             NULL, p_response); 
     1978            if (rc==PJ_SUCCESS && realm) { 
     1979                pj_stun_msg_add_generic_string_attr(pool, *p_response, 
     1980                                                    PJ_STUN_ATTR_REALM,  
     1981                                                    realm); 
     1982            } 
     1983        } 
     1984        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_UNAUTHORIZED); 
     1985    } 
     1986 
     1987    /* Next check that USERNAME is present */ 
     1988    auser = (const pj_stun_username_attr*) 
     1989            pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0); 
     1990    if (auser == NULL) { 
     1991        if (pool && p_response) { 
     1992            pj_status_t rc; 
     1993 
     1994            rc = pj_stun_msg_create_response(pool, msg,  
     1995                                             PJ_STUN_STATUS_MISSING_USERNAME,  
     1996                                             NULL, p_response); 
     1997            if (rc==PJ_SUCCESS && realm) { 
     1998                pj_stun_msg_add_generic_string_attr(pool, *p_response, 
     1999                                                    PJ_STUN_ATTR_REALM,  
     2000                                                    realm); 
     2001            } 
     2002        } 
     2003        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_USERNAME); 
     2004    } 
     2005 
     2006    /* Check if username match */ 
     2007    if (username && pj_stricmp(&auser->value, username) != 0) { 
     2008        /* Username mismatch */ 
     2009        if (pool && p_response) { 
     2010            pj_status_t rc; 
     2011 
     2012            rc = pj_stun_msg_create_response(pool, msg,  
     2013                                             PJ_STUN_STATUS_WRONG_USERNAME,  
     2014                                             NULL, p_response); 
     2015            if (rc==PJ_SUCCESS && realm) { 
     2016                pj_stun_msg_add_generic_string_attr(pool, *p_response, 
     2017                                                    PJ_STUN_ATTR_REALM,  
     2018                                                    realm); 
     2019            } 
     2020        } 
     2021        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_WRONG_USERNAME); 
     2022    } 
     2023 
     2024    /* Next check that REALM is present */ 
     2025    arealm = (const pj_stun_realm_attr*) 
     2026             pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0); 
     2027    if (realm != NULL && arealm == NULL) { 
     2028        /* Long term credential is required */ 
     2029        if (pool && p_response) { 
     2030            pj_status_t rc; 
     2031 
     2032            rc = pj_stun_msg_create_response(pool, msg,  
     2033                                             PJ_STUN_STATUS_MISSING_REALM,  
     2034                                             NULL, p_response); 
     2035            if (rc==PJ_SUCCESS) { 
     2036                pj_stun_msg_add_generic_string_attr(pool, *p_response, 
     2037                                                    PJ_STUN_ATTR_REALM,  
     2038                                                    realm); 
     2039            } 
     2040        } 
     2041        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_REALM); 
     2042 
     2043    } else if (realm != NULL && arealm != NULL) { 
     2044 
     2045 
     2046    } else if (realm == NULL && arealm != NULL) { 
     2047        /* We want to use short term credential, but client uses long 
     2048         * term credential. The draft doesn't mention anything about 
     2049         * switching between long term and short term. 
     2050         */ 
     2051        PJ_TODO(SWITCHING_BETWEEN_SHORT_TERM_AND_LONG_TERM); 
     2052    } 
     2053 
     2054    PJ_TODO(CONTINUE_IMPLEMENTATION); 
     2055 
     2056    return PJ_SUCCESS; 
     2057} 
     2058 
     2059 
Note: See TracChangeset for help on using the changeset viewer.