STATUS deserializeStunPacket()

in src/source/Stun/Stun.c [517:1062]


STATUS deserializeStunPacket(PBYTE pStunBuffer, UINT32 bufferSize, PBYTE password, UINT32 passwordLen, PStunPacket* ppStunPacket)
{
    ENTERS();
    STATUS retStatus = STATUS_SUCCESS;
    UINT32 attributeCount = 0, allocationSize, attributeSize, i = 0, j, magicCookie, hmacLen, crc32, data;
    UINT32 stunMagicCookie = STUN_HEADER_MAGIC_COOKIE;
    UINT16 size, paddedLength, ipFamily, messageLength;
    INT64 data64;
    PStunAttributeHeader pStunAttributeHeader, pStunAttributes, pDestAttribute;
    PStunHeader pStunHeader = (PStunHeader) pStunBuffer;
    PStunPacket pStunPacket = NULL;
    StunAttributeHeader stunAttributeHeader;
    PStunAttributeAddress pStunAttributeAddress;
    PStunAttributeUsername pStunAttributeUsername;
    PStunAttributeMessageIntegrity pStunAttributeMessageIntegrity;
    PStunAttributeFingerprint pStunAttributeFingerprint;
    PStunAttributePriority pStunAttributePriority;
    PStunAttributeLifetime pStunAttributeLifetime;
    PStunAttributeChangeRequest pStunAttributeChangeRequest;
    PStunAttributeRequestedTransport pStunAttributeRequestedTransport;
    PStunAttributeRealm pStunAttributeRealm;
    PStunAttributeNonce pStunAttributeNonce;
    PStunAttributeErrorCode pStunAttributeErrorCode;
    PStunAttributeIceControl pStunAttributeIceControl;
    PStunAttributeData pStunAttributeData;
    PStunAttributeChannelNumber pStunAttributeChannelNumber;
    BOOL fingerprintFound = FALSE, messaageIntegrityFound = FALSE;
    PBYTE pData, pTransaction;

    CHK(pStunBuffer != NULL && ppStunPacket != NULL, STATUS_NULL_ARG);
    CHK(bufferSize >= STUN_HEADER_LEN, STATUS_INVALID_ARG);

    if (!isBigEndian()) {
        stunMagicCookie = STUN_HEADER_MAGIC_COOKIE_LE;
    }

    // Copy and fix-up the header
    messageLength = (UINT16) getInt16(*(PUINT16) ((PBYTE) pStunHeader + STUN_HEADER_TYPE_LEN));
    magicCookie = (UINT32) getInt32(*(PUINT32) ((PBYTE) pStunHeader + STUN_HEADER_TYPE_LEN + STUN_HEADER_DATA_LEN));

    // Validate the specified size
    CHK(bufferSize >= messageLength + STUN_HEADER_LEN, STATUS_INVALID_ARG);

    // Validate the magic cookie
    CHK(magicCookie == STUN_HEADER_MAGIC_COOKIE, STATUS_STUN_MAGIC_COOKIE_MISMATCH);

    // Calculate the required size by getting the number of attributes
    pStunAttributes = (PStunAttributeHeader) (pStunBuffer + STUN_HEADER_LEN);
    pStunAttributeHeader = pStunAttributes;
    allocationSize = SIZEOF(StunPacket);
    while ((PBYTE) pStunAttributeHeader < (PBYTE) pStunAttributes + messageLength) {
        // Copy/Swap tne attribute header
        stunAttributeHeader.type = (STUN_ATTRIBUTE_TYPE) getInt16(*(PUINT16) pStunAttributeHeader);
        stunAttributeHeader.length = (UINT16) getInt16(*(PUINT16) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_TYPE_LEN));

        // Zero out for before iteration
        attributeSize = 0;

        // Calculate the padded size
        paddedLength = (UINT16) ROUND_UP(stunAttributeHeader.length, 4);

        // Check the type, get the allocation size and validate the length for each attribute
        switch (stunAttributeHeader.type) {
            case STUN_ATTRIBUTE_TYPE_MAPPED_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_XOR_MAPPED_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_RESPONSE_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_SOURCE_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_REFLECTED_FROM:
            case STUN_ATTRIBUTE_TYPE_XOR_RELAYED_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_XOR_PEER_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_CHANGED_ADDRESS:
                attributeSize = SIZEOF(StunAttributeAddress);

                // Cast, swap and get the size
                pStunAttributeAddress = (PStunAttributeAddress) pStunAttributeHeader;
                ipFamily = (UINT16) getInt16(pStunAttributeAddress->address.family) & (UINT16) 0x00ff;

                // Address family and the port
                size = STUN_ATTRIBUTE_ADDRESS_HEADER_LEN + ((ipFamily == KVS_IP_FAMILY_TYPE_IPV4) ? IPV4_ADDRESS_LENGTH : IPV6_ADDRESS_LENGTH);

                CHK(stunAttributeHeader.length == size, STATUS_STUN_INVALID_ADDRESS_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);
                break;

            case STUN_ATTRIBUTE_TYPE_USERNAME:
                attributeSize = SIZEOF(StunAttributeUsername);

                // Validate the size of the length against the max value of username
                CHK(stunAttributeHeader.length <= STUN_MAX_USERNAME_LEN, STATUS_STUN_INVALID_USERNAME_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                // Add the length of the string itself
                attributeSize += paddedLength;
                break;

            case STUN_ATTRIBUTE_TYPE_PRIORITY:
                attributeSize = SIZEOF(StunAttributePriority);

                CHK(stunAttributeHeader.length == STUN_ATTRIBUTE_PRIORITY_LEN, STATUS_STUN_INVALID_PRIORITY_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                break;

            case STUN_ATTRIBUTE_TYPE_USE_CANDIDATE:
            case STUN_ATTRIBUTE_TYPE_DONT_FRAGMENT:
                attributeSize = SIZEOF(StunAttributeFlag);

                CHK(stunAttributeHeader.length == STUN_ATTRIBUTE_FLAG_LEN, STATUS_STUN_INVALID_USE_CANDIDATE_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                break;

            case STUN_ATTRIBUTE_TYPE_LIFETIME:
                attributeSize = SIZEOF(StunAttributeLifetime);

                CHK(stunAttributeHeader.length == STUN_ATTRIBUTE_LIFETIME_LEN, STATUS_STUN_INVALID_LIFETIME_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                break;

            case STUN_ATTRIBUTE_TYPE_CHANGE_REQUEST:
                attributeSize = SIZEOF(StunAttributeChangeRequest);

                CHK(stunAttributeHeader.length == STUN_ATTRIBUTE_CHANGE_REQUEST_FLAG_LEN, STATUS_STUN_INVALID_CHANGE_REQUEST_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                break;

            case STUN_ATTRIBUTE_TYPE_REQUESTED_TRANSPORT:
                attributeSize = SIZEOF(StunAttributeRequestedTransport);

                CHK(stunAttributeHeader.length == STUN_ATTRIBUTE_REQUESTED_TRANSPORT_PROTOCOL_LEN,
                    STATUS_STUN_INVALID_REQUESTED_TRANSPORT_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                break;

            case STUN_ATTRIBUTE_TYPE_REALM:
                attributeSize = SIZEOF(StunAttributeRealm);

                // Validate the size of the length against the max value of realm
                CHK(stunAttributeHeader.length <= STUN_MAX_REALM_LEN, STATUS_STUN_INVALID_REALM_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                // Add the length of the string itself
                attributeSize += paddedLength;
                break;

            case STUN_ATTRIBUTE_TYPE_NONCE:
                attributeSize = SIZEOF(StunAttributeNonce);

                // Validate the size of the length against the max value of nonce
                CHK(stunAttributeHeader.length <= STUN_MAX_NONCE_LEN, STATUS_STUN_INVALID_NONCE_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                // Add the length of the string itself
                attributeSize += paddedLength;
                break;

            case STUN_ATTRIBUTE_TYPE_ERROR_CODE:
                attributeSize = SIZEOF(StunAttributeErrorCode);

                // Validate the size of the length against the max value of error phrase
                CHK(stunAttributeHeader.length <= STUN_MAX_ERROR_PHRASE_LEN, STATUS_STUN_INVALID_ERROR_CODE_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                // Add the length of the string itself
                attributeSize += paddedLength;
                break;

            case STUN_ATTRIBUTE_TYPE_ICE_CONTROLLED:
            case STUN_ATTRIBUTE_TYPE_ICE_CONTROLLING:
                attributeSize = SIZEOF(StunAttributeIceControl);

                CHK(stunAttributeHeader.length == STUN_ATTRIBUTE_ICE_CONTROL_LEN, STATUS_STUN_INVALID_ICE_CONTROL_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                break;

            case STUN_ATTRIBUTE_TYPE_DATA:
                attributeSize = SIZEOF(StunAttributeData);

                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                // Add the length of the data itself
                attributeSize += paddedLength;
                break;

            case STUN_ATTRIBUTE_TYPE_CHANNEL_NUMBER:
                attributeSize = SIZEOF(StunAttributeChannelNumber);

                CHK(stunAttributeHeader.length == STUN_ATTRIBUTE_CHANNEL_NUMBER_LEN, STATUS_STUN_INVALID_CHANNEL_NUMBER_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound && !messaageIntegrityFound, STATUS_STUN_ATTRIBUTES_AFTER_FINGERPRINT_MESSAGE_INTEGRITY);

                break;

            case STUN_ATTRIBUTE_TYPE_MESSAGE_INTEGRITY:
                attributeSize = SIZEOF(StunAttributeMessageIntegrity);
                CHK(stunAttributeHeader.length == STUN_HMAC_VALUE_LEN, STATUS_STUN_INVALID_MESSAGE_INTEGRITY_ATTRIBUTE_LENGTH);
                CHK(!messaageIntegrityFound, STATUS_STUN_MULTIPLE_MESSAGE_INTEGRITY_ATTRIBUTES);
                CHK(!fingerprintFound, STATUS_STUN_MESSAGE_INTEGRITY_AFTER_FINGERPRINT);
                messaageIntegrityFound = TRUE;
                break;

            case STUN_ATTRIBUTE_TYPE_FINGERPRINT:
                attributeSize = SIZEOF(StunAttributeFingerprint);
                CHK(stunAttributeHeader.length == STUN_ATTRIBUTE_FINGERPRINT_LEN, STATUS_STUN_INVALID_FINGERPRINT_ATTRIBUTE_LENGTH);
                CHK(!fingerprintFound, STATUS_STUN_MULTIPLE_FINGERPRINT_ATTRIBUTES);
                fingerprintFound = TRUE;
                break;

            default:
                // Do nothing - skip and decrement the count as it will be incremented below anyway
                attributeCount--;
                break;
        }

        allocationSize += attributeSize;
        attributeCount++;

        CHK(attributeCount <= STUN_ATTRIBUTE_MAX_COUNT, STATUS_STUN_MAX_ATTRIBUTE_COUNT);

        // Increment the attributes pointer and account for the length
        pStunAttributeHeader = (PStunAttributeHeader) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN + paddedLength);
    }

    // Account for the attribute pointer array
    allocationSize += attributeCount * SIZEOF(PStunAttributeHeader);

    // Allocate the necessary storage and set the pointers for the attributes
    CHK(NULL != (pStunPacket = MEMCALLOC(1, allocationSize)), STATUS_NOT_ENOUGH_MEMORY);

    // Copy/swap the header
    pStunPacket->header.stunMessageType = (UINT16) getInt16(pStunHeader->stunMessageType);
    pStunPacket->header.messageLength = messageLength;
    pStunPacket->header.magicCookie = magicCookie;
    MEMCPY(pStunPacket->header.transactionId, pStunHeader->transactionId, STUN_TRANSACTION_ID_LEN);

    // Store the actual allocation size
    pStunPacket->allocationSize = allocationSize;

    // Set the attribute array pointer
    pStunPacket->attributeList = (PStunAttributeHeader*) (pStunPacket + 1);

    // Set the count of the processed attributes only
    pStunPacket->attributesCount = attributeCount;

    // Set the attribute buffer start
    pDestAttribute = (PStunAttributeHeader) (pStunPacket->attributeList + attributeCount);

    // Reset the attributes to go over the array and convert
    pStunAttributeHeader = pStunAttributes;

    // Start packaging the attributes
    while (((PBYTE) pStunAttributeHeader < (PBYTE) pStunAttributes + pStunPacket->header.messageLength) && i < attributeCount) {
        // Set the array entry first
        pStunPacket->attributeList[i++] = pDestAttribute;

        // Copy/Swap tne attribute header
        pDestAttribute->type = (STUN_ATTRIBUTE_TYPE) getInt16(pStunAttributeHeader->type);
        pDestAttribute->length = (UINT16) getInt16(pStunAttributeHeader->length);

        // Zero out for before iteration
        attributeSize = 0;

        // Calculate the padded size
        paddedLength = (UINT16) ROUND_UP(pDestAttribute->length, 4);

        switch (pDestAttribute->type) {
            case STUN_ATTRIBUTE_TYPE_MAPPED_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_XOR_MAPPED_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_RESPONSE_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_SOURCE_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_REFLECTED_FROM:
            case STUN_ATTRIBUTE_TYPE_XOR_RELAYED_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_XOR_PEER_ADDRESS:
            case STUN_ATTRIBUTE_TYPE_CHANGED_ADDRESS:
                pStunAttributeAddress = (PStunAttributeAddress) pDestAttribute;

                // Copy the entire structure and swap
                MEMCPY(&pStunAttributeAddress->address, (PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN,
                       pStunAttributeAddress->attribute.length);
                pStunAttributeAddress->address.family = (UINT16) getInt16(pStunAttributeAddress->address.family) & (UINT16) 0x00ff;
                attributeSize = SIZEOF(StunAttributeAddress);

                // Special handling for the XOR mapped address
                if (pStunAttributeAddress->attribute.type == STUN_ATTRIBUTE_TYPE_XOR_MAPPED_ADDRESS ||
                    pStunAttributeAddress->attribute.type == STUN_ATTRIBUTE_TYPE_XOR_RELAYED_ADDRESS) {
                    // XOR the port with high-bits of the magic cookie
                    pStunAttributeAddress->address.port ^= (UINT16) stunMagicCookie;

                    // Perform the XOR-ing
                    data = *(PUINT32) pStunAttributeAddress->address.address;
                    data ^= stunMagicCookie;
                    *(PUINT32) pStunAttributeAddress->address.address = data;

                    if (pStunAttributeAddress->address.family == KVS_IP_FAMILY_TYPE_IPV6) {
                        // Process the rest of 12 bytes for IPv6
                        pData = &pStunAttributeAddress->address.address[SIZEOF(UINT32)];
                        pTransaction = pStunPacket->header.transactionId;
                        for (j = 0; j < STUN_TRANSACTION_ID_LEN; j++) {
                            *pData++ ^= *pTransaction++;
                        }
                    }
                }

                break;

            case STUN_ATTRIBUTE_TYPE_USERNAME:
                pStunAttributeUsername = (PStunAttributeUsername) pDestAttribute;

                // Set the padded length
                pStunAttributeUsername->paddedLength = paddedLength;

                // Set the pointer following the structure
                pStunAttributeUsername->userName = (PCHAR) (pStunAttributeUsername + 1);

                // Copy the padded user name
                MEMCPY(pStunAttributeUsername->userName, (PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN,
                       pStunAttributeUsername->paddedLength);
                attributeSize = SIZEOF(StunAttributeUsername) + pStunAttributeUsername->paddedLength;

                break;

            case STUN_ATTRIBUTE_TYPE_PRIORITY:
                pStunAttributePriority = (PStunAttributePriority) pDestAttribute;

                pStunAttributePriority->priority = (UINT32) getInt32(*(PUINT32) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN));

                attributeSize = SIZEOF(StunAttributePriority);

                break;

            case STUN_ATTRIBUTE_TYPE_USE_CANDIDATE:
            case STUN_ATTRIBUTE_TYPE_DONT_FRAGMENT:
                attributeSize = SIZEOF(StunAttributeFlag);

                break;

            case STUN_ATTRIBUTE_TYPE_LIFETIME:
                pStunAttributeLifetime = (PStunAttributeLifetime) pDestAttribute;

                pStunAttributeLifetime->lifetime = (UINT32) getInt32(*(PUINT32) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN));

                attributeSize = SIZEOF(StunAttributeLifetime);

                break;

            case STUN_ATTRIBUTE_TYPE_CHANGE_REQUEST:
                pStunAttributeChangeRequest = (PStunAttributeChangeRequest) pDestAttribute;

                pStunAttributeChangeRequest->changeFlag = (UINT32) getInt32(*(PUINT32) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN));

                attributeSize = SIZEOF(StunAttributeChangeRequest);

                break;

            case STUN_ATTRIBUTE_TYPE_REQUESTED_TRANSPORT:
                pStunAttributeRequestedTransport = (PStunAttributeRequestedTransport) pDestAttribute;

                MEMCPY(pStunAttributeRequestedTransport->protocol, (PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN,
                       STUN_ATTRIBUTE_REQUESTED_TRANSPORT_PROTOCOL_LEN);

                attributeSize = SIZEOF(StunAttributeRequestedTransport);

                break;

            case STUN_ATTRIBUTE_TYPE_REALM:
                pStunAttributeRealm = (PStunAttributeRealm) pDestAttribute;

                // Set the padded length
                pStunAttributeRealm->paddedLength = paddedLength;

                // Set the pointer following the structure
                pStunAttributeRealm->realm = (PCHAR) (pStunAttributeRealm + 1);

                // Copy the padded realm
                MEMCPY(pStunAttributeRealm->realm, (PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN, pStunAttributeRealm->paddedLength);
                attributeSize = SIZEOF(StunAttributeRealm) + pStunAttributeRealm->paddedLength;

                break;

            case STUN_ATTRIBUTE_TYPE_NONCE:
                pStunAttributeNonce = (PStunAttributeNonce) pDestAttribute;

                // Set the padded length
                pStunAttributeNonce->paddedLength = paddedLength;

                // Set the pointer following the structure
                pStunAttributeNonce->nonce = (PBYTE) (pStunAttributeNonce + 1);

                // Copy the padded nonce
                MEMCPY(pStunAttributeNonce->nonce, (PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN, pStunAttributeNonce->paddedLength);
                attributeSize = SIZEOF(StunAttributeNonce) + pStunAttributeNonce->paddedLength;

                break;

            case STUN_ATTRIBUTE_TYPE_ERROR_CODE:
                pStunAttributeErrorCode = (PStunAttributeErrorCode) pDestAttribute;

                // Set the padded length
                pStunAttributeErrorCode->paddedLength = paddedLength;

                // swap the error code
                pStunAttributeErrorCode->errorCode =
                    GET_STUN_ERROR_CODE(((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN + STUN_ERROR_CODE_PACKET_ERROR_CLASS_OFFSET),
                                        ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN + STUN_ERROR_CODE_PACKET_ERROR_CODE_OFFSET));

                // Set the pointer following the structure
                pStunAttributeErrorCode->errorPhrase = (PCHAR) (pStunAttributeErrorCode + 1);

                // Copy the padded error phrase
                MEMCPY(pStunAttributeErrorCode->errorPhrase,
                       ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN + STUN_ERROR_CODE_PACKET_ERROR_PHRASE_OFFSET),
                       pStunAttributeErrorCode->paddedLength - STUN_ERROR_CODE_PACKET_ERROR_PHRASE_OFFSET);
                attributeSize = SIZEOF(StunAttributeErrorCode) + pStunAttributeErrorCode->paddedLength;

                break;

            case STUN_ATTRIBUTE_TYPE_ICE_CONTROLLED:
            case STUN_ATTRIBUTE_TYPE_ICE_CONTROLLING:
                pStunAttributeIceControl = (PStunAttributeIceControl) pDestAttribute;

                // Deal with the alignment
                MEMCPY(&data64, (PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN, SIZEOF(INT64));
                data64 = (INT64) getInt64(data64);

                // Swap the bits
                MEMCPY((PBYTE) pStunAttributeIceControl + SIZEOF(StunAttributeIceControl) - SIZEOF(UINT64), &data64, SIZEOF(INT64));

                attributeSize = SIZEOF(StunAttributeIceControl);

                break;

            case STUN_ATTRIBUTE_TYPE_DATA:
                pStunAttributeData = (PStunAttributeData) pDestAttribute;

                // Set the padded length
                pStunAttributeData->paddedLength = paddedLength;

                // Set the pointer following the structure
                pStunAttributeData->data = (PBYTE) (pStunAttributeData + 1);

                // Copy the padded nonce
                MEMCPY(pStunAttributeData->data, (PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN, pStunAttributeData->paddedLength);
                attributeSize = SIZEOF(StunAttributeData) + pStunAttributeData->paddedLength;

                break;

            case STUN_ATTRIBUTE_TYPE_CHANNEL_NUMBER:
                pStunAttributeChannelNumber = (PStunAttributeChannelNumber) pDestAttribute;

                pStunAttributeChannelNumber->channelNumber = (UINT16) getInt16(*(PUINT16) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN));

                pStunAttributeChannelNumber->reserve = 0;

                attributeSize = SIZEOF(StunAttributeChannelNumber);

                break;

            case STUN_ATTRIBUTE_TYPE_MESSAGE_INTEGRITY:
                CHK(password != NULL, STATUS_NULL_ARG);
                CHK(passwordLen != 0, STATUS_INVALID_ARG);

                pStunAttributeMessageIntegrity = (PStunAttributeMessageIntegrity) pDestAttribute;

                // Copy the message integrity
                attributeSize = SIZEOF(StunAttributeMessageIntegrity);

                // Validate the HMAC
                // Fix-up the packet length
                size = (UINT16) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN + STUN_HMAC_VALUE_LEN - pStunBuffer - STUN_HEADER_LEN);
                putInt16((PINT16) (pStunBuffer + STUN_HEADER_TYPE_LEN), size);

                // The size of the message size in bytes should be a multiple of 64 per rfc
                // CHK((size & 0x003f) == 0, STATUS_WEBRTC_STUN_MESSAGE_INTEGRITY_SIZE_ALIGNMENT);

                // Calculate the HMAC for the integrity of the packet including STUN header and excluding the integrity attribute
                size = (UINT16) ((PBYTE) pStunAttributeHeader - pStunBuffer);
                KVS_SHA1_HMAC(password, (INT32) passwordLen, pStunBuffer, size, pStunAttributeMessageIntegrity->messageIntegrity, &hmacLen);

                // Reset the original size in the buffer
                putInt16((PINT16) (pStunBuffer + STUN_HEADER_TYPE_LEN), pStunPacket->header.messageLength);

                // Validate the HMAC
                CHK(0 ==
                        MEMCMP(pStunAttributeMessageIntegrity->messageIntegrity, (PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN,
                               STUN_HMAC_VALUE_LEN),
                    STATUS_STUN_MESSAGE_INTEGRITY_MISMATCH);

                break;

            case STUN_ATTRIBUTE_TYPE_FINGERPRINT:
                pStunAttributeFingerprint = (PStunAttributeFingerprint) pDestAttribute;

                // Copy the use fingerprint value
                pStunAttributeFingerprint->crc32Fingerprint =
                    (UINT32) getInt32(*(PUINT32) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN));
                attributeSize = SIZEOF(StunAttributeFingerprint);

                // Validate the Fingerprint
                // Fix-up the packet length
                size = (UINT16) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN + STUN_ATTRIBUTE_FINGERPRINT_LEN - pStunBuffer -
                                 STUN_HEADER_LEN);
                putInt16((PINT16) (pStunBuffer + STUN_HEADER_TYPE_LEN), size);

                // Calculate the fingerprint
                size = (UINT16) ((PBYTE) pStunAttributeHeader - pStunBuffer);

                crc32 = COMPUTE_CRC32(pStunBuffer, (UINT32) size) ^ STUN_FINGERPRINT_ATTRIBUTE_XOR_VALUE;

                // Reset the original size in the buffer
                putInt16((PINT16) (pStunBuffer + STUN_HEADER_TYPE_LEN), pStunPacket->header.messageLength);

                // Validate the fingerprint
                CHK(crc32 == pStunAttributeFingerprint->crc32Fingerprint, STATUS_STUN_FINGERPRINT_MISMATCH);

                break;

            default:
                // Skip over the unknown attributes
                break;
        }

        // Increment the attributes pointer and account for the length
        pStunAttributeHeader = (PStunAttributeHeader) ((PBYTE) pStunAttributeHeader + STUN_ATTRIBUTE_HEADER_LEN + paddedLength);

        // Set the destination
        pDestAttribute = (PStunAttributeHeader) ((PBYTE) pDestAttribute + attributeSize);
    }

CleanUp:

    if (STATUS_FAILED(retStatus)) {
        freeStunPacket(&pStunPacket);
    }

    if (ppStunPacket != NULL) {
        *ppStunPacket = pStunPacket;
    }

    CHK_LOG_ERR(retStatus);

    LEAVES();
    return retStatus;
}