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

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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 
Note: See TracChangeset for help on using the changeset viewer.