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;
}