📄 record.c
字号:
if (diff > WINDOW_SIZE) { /* Too old, beyond the window's */
return -1; /* left edge. */
}
if (conn->mask & ((UINT32)1 << (diff - 1))) { /* Inside window, but */
return -1; /* marked as having been seen. */
}
return RET_OK; /* Passed all tests. */
}
/*
* Update the read sequence number.
* Assumes that seqNum has previously been checked and found valid.
*/
static void
wtls_rec_update_seqnum (UINT16 seqnum, wtls_connection_t *conn)
{
UINT16 diff;
if (seqnum >= conn->read.seqnum) {
/* A new larger sequence number, we have to update the window. */
diff = seqnum - conn->read.seqnum;
if (diff < WINDOW_SIZE) { /* Move the window */
conn->mask <<= (diff + 1);
conn->mask |= 1;
}
else {
conn->mask = 1;
}
conn->read.seqnum = seqnum + 1;
}
else {
/* Set one of the bits in the window. */
diff = conn->read.seqnum - seqnum;
conn->mask |= ((UINT32)1 << (diff - 1));
}
}
/*
* Decrypt, check padding and MAC, and decompress a record.
*/
INT16
wtls_rec_decrypt_record (wtls_connection_state *cstate, wtls_record_t *rec)
{
INT16 i;
UINT16 len;
UINT8 paddinglen;
BYTE md[MAX_HASH_MAC_SIZE];
/* Decrypt: */
if (cstate->cobj.type == CIPHER_TYPE_BLOCK) {
BYTE iv1[MAX_IV_SIZE];
/* Fix the per-record IV */
for (i = 0; i < cstate->cobj.iv_size; i += 2) {
iv1[i] = cstate->iv[i] ^ (rec->seqnum >> 8);
iv1[i + 1] = cstate->iv[i + 1] ^ (rec->seqnum & 0xff);
}
len = rec->length;
if (wtls_crypto_decrypt (&(cstate->cobj), cstate->encryption_key, iv1,
rec->fragment, rec->length,
rec->fragment) < 0) {
return -1;
}
/* Check padding */
paddinglen = rec->fragment[len - 1];
if (len < paddinglen + 1) {
wtls_err_set (ERR_GENERAL, ERR_BAD_PADDING,
1, ALERT_LEVEL_WARNING, ALERT_DESC_DECRYPTION_FAILED);
return -1;
}
rec->length = len - (paddinglen + 1);
for (i = 0; i < paddinglen; i++) {
if (rec->fragment[len - i - 2] != paddinglen) {
wtls_err_set (ERR_GENERAL, ERR_BAD_PADDING,
1, ALERT_LEVEL_WARNING, ALERT_DESC_DECRYPTION_FAILED);
return -1;
}
}
}
else if (cstate->cobj.bulk_cipher_alg != CIPHER_NULL) {
/* Currently we have no stream ciphers except the NULL alg. */
}
/* Check MAC: */
if (cstate->cobj.mac_size > 0) {
if (rec->length < cstate->cobj.mac_size) {
wtls_err_set (ERR_GENERAL, ERR_BAD_MAC,
1, ALERT_LEVEL_WARNING, ALERT_DESC_BAD_RECORD_MAC);
return -1;
}
rec->length -= cstate->cobj.mac_size;
if (wtls_crypto_MAC (&(cstate->cobj), cstate->mac_secret,
rec->fragment, rec->length,
rec->seqnum, rec->rec_type, md) < 0) {
return -1;
}
/* Compare with MAC in decrypted record. */
for (i = 0; i < cstate->cobj.mac_size; i++) {
if (rec->fragment[rec->length + i] != md[i]) {
wtls_err_set (ERR_GENERAL, ERR_BAD_MAC,
1, ALERT_LEVEL_WARNING, ALERT_DESC_BAD_RECORD_MAC);
return -1;
}
}
}
/* Decompress: */
if (cstate->cobj.compression_alg != COMPRESS_NULL) {
/* Currently we have no compression algorithms. */
}
return RET_OK;
}
/*
* Get the next incoming record from this connection's list of
* incoming records, and delete it from that list.
*/
INT16
wtls_rec_next_msg (void *connptr, void **pprec, SDL_Boolean same_SDU)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec;
UINT16 msg_type;
rec = wtls_main_peek_incoming_message (conn->cm_proc);
if ((rec == NULL) ||
(rec->is_first && (same_SDU == SDL_True))) {
return RET_QUEUE_EMPTY;
}
rec = wtls_main_pop_incoming_message (conn->cm_proc);
msg_type = rec->rec_type & RECTYPE_CONTENT_TYPE;
/* STEP 1: does the record have a sequence number? */
if (!(rec->rec_type & RECTYPE_SEQNUM)) {
/* Is it allowed to leave out the sequence number? */
if ((msg_type == CONTENT_TYPE_CCS) ||
(msg_type == CONTENT_TYPE_HANDSHAKE) ||
(conn->read.seqnum_mode == SEQNUMMODE_EXPLICIT)) {
wtls_rec_delete_record (rec);
return RET_NEXT_MESSAGE;
}
}
/* STEP 2: does the use cipher spec bit agree with our current state? */
if ((rec->rec_type & RECTYPE_USE_CS) && !conn->read.use_cipher_spec) {
wtls_rec_delete_record (rec);
return RET_NEXT_MESSAGE;
}
if (!(rec->rec_type & RECTYPE_USE_CS) && conn->read.use_cipher_spec) {
/* Certain alerts are allowed to be transmitted in the clear. */
if (msg_type == CONTENT_TYPE_ALERT) {
UINT8 alertdesc = rec->fragment[1];
if ((alertdesc == ALERT_DESC_NO_CONNECTION) ||
(alertdesc == ALERT_DESC_BAD_RECORD_MAC) ||
(alertdesc == ALERT_DESC_DECRYPTION_FAILED) ||
(alertdesc == ALERT_DESC_RECORD_OVERFLOW) ||
(alertdesc == ALERT_DESC_DECOMPRESSION_FAILURE)) {
goto rec_ok;
}
}
wtls_rec_delete_record (rec);
return RET_NEXT_MESSAGE;
}
rec_ok:
*pprec = rec;
/* As a preparation to decryption, check if we need to
* refresh the keys. */
if (rec->rec_type & RECTYPE_USE_CS) {
UINT16 s;
/* Time for key refresh? */
s = (~0 << conn->read.key_refresh_rate) & (rec->seqnum);
if (s != conn->read.last_refresh) {
conn->read.last_refresh = s;
return RET_KEY_REFRESH;
}
}
return RET_OK;
}
INT16
wtls_rec_continue_next_msg (void *connptr, void *recptr,
SDL_Natural *pmsg_type,
void **pbuf, SDL_Natural *pbuflen,
SDL_Natural *alert_level,
SDL_Natural *alert_desc)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec = (wtls_record_t *)recptr;
wtls_alert_t alert;
UINT16 msg_type = rec->rec_type & RECTYPE_CONTENT_TYPE;
*pbuf = NULL;
*pbuflen = 0;
/* STEP 3: If this record is encrypted, try to decrypt it.
* If decryption fails, send a warning Alert and get next message. */
if (rec->rec_type & RECTYPE_USE_CS) {
if (wtls_rec_decrypt_record (&(conn->read), rec) < 0) {
SDL_Integer errtype, errcode, sendalert;
wtls_rec_delete_record (rec);
wtls_err_get (&errtype, &errcode, &sendalert,
(SDL_Integer *)alert_level,
(SDL_Integer *)alert_desc);
if (*alert_level == ALERT_LEVEL_WARNING) {
return RET_DECRYPTION_FAILED;
}
return -1;
}
}
/* STEP 4: If it is an alert, verify the checksum.
* We accept checksums of any of the last 4 messages we sent. */
if (msg_type == CONTENT_TYPE_ALERT) {
INT16 i, limit;
wap_cvt_t cvt_obj;
wap_cvt_init (&cvt_obj, WAP_CVT_DECODE, rec->fragment, rec->length);
if (!wtls_cvt_alert (&cvt_obj, &alert)) {
/* Error in message format, ignore record silently. */
wtls_err_set (ERR_GENERAL, ERR_DECODING, 1,
ALERT_LEVEL_CRITICAL, ALERT_DESC_DECODE_ERROR);
wtls_rec_delete_record (rec);
return RET_NEXT_MESSAGE;
}
limit = MIN (4, conn->num_cksums);
for (i = 0; i < limit; i++) {
if (alert.checksum == conn->write_cksum[i]) {
/* We found a match. */
break;
}
}
#ifndef TEST_WTLS
if (i == limit) {
/* No match, ignore record silently. */
wtls_rec_delete_record (rec);
return RET_NEXT_MESSAGE;
}
#endif
/* Fatal Alert sent in cleartext should be treated as critical. */
if ((alert.level == ALERT_LEVEL_FATAL) &&
(!(rec->rec_type & RECTYPE_USE_CS))) {
alert.level = ALERT_LEVEL_CRITICAL;
}
*alert_level = (SDL_Natural)alert.level;
*alert_desc = (SDL_Natural)alert.description;
}
/* STEP 5: If it is an alert of type "no connection", go to step 6.
* Otherwise, check the sequence number. */
if ((msg_type != CONTENT_TYPE_ALERT) ||
(alert.description != ALERT_DESC_NO_CONNECTION)) {
if (wtls_rec_check_seqnum (rec->seqnum, conn) < 0) {
/* Invalid sequence number, ignore silently. */
wtls_rec_delete_record (rec);
return RET_NEXT_MESSAGE;
}
}
/* Handshake messages must increment sequence numbers by 1. */
/* How can we check this? */
/* (Consider, e.g., if this is the FIRST handshake message?) */
/* STEP 6: Increment the sequence number. */
wtls_rec_update_seqnum (rec->seqnum, conn);
#ifdef LOG_WTLS
wtls_log_msg (0, "\n--------PROCESSING RECEIVED RECORD--------\n");
wtls_log_record (rec, LOG_INCOMING);
#endif
/* STEP 7: Retrieve buffer and delete record. */
if ((msg_type == CONTENT_TYPE_HANDSHAKE) &&
(rec->fragment != NULL) &&
(rec->fragment[0] == HANDSHK_HELLO_REQUEST)) {
msg_type = CONTENT_TYPE_HELLO_REQUEST;
}
*pbuflen = rec->length;
*pbuf = rec->fragment;
if ((msg_type == CONTENT_TYPE_CCS) ||
(msg_type == CONTENT_TYPE_ALERT) ||
(msg_type == CONTENT_TYPE_HELLO_REQUEST)) {
DEALLOC (&(rec->fragment));
*pbuf = NULL;
*pbuflen = 0;
}
rec->fragment = NULL;
*pmsg_type = msg_type;
wtls_rec_delete_record (rec);
if (msg_type == CONTENT_TYPE_ALERT) {
if (alert.description == ALERT_DESC_TIME_REQUIRED) {
return RET_TIME_REQUIRED;
}
else {
return RET_ALERT;
}
}
return RET_OK;
}
/*
* Routines to handle the lists of records.
*/
/*
* Add a record at the end of a list of records.
*/
void
wtls_rec_list_append (wtls_record_t *rec, wtls_record_t **rec_list)
{
rec->next = NULL;
if (*rec_list == NULL) {
*rec_list = rec;
}
else {
wtls_record_t *p = *rec_list;
while (p->next != NULL) {
p = p->next;
}
p->next = rec;
}
}
/*
* Remove, and return, the first record in a list of records.
*/
wtls_record_t *
wtls_rec_list_pop (wtls_record_t **rec_list)
{
wtls_record_t *rec = *rec_list;
if (rec != NULL) {
*rec_list = rec->next;
rec->next = NULL;
}
return rec;
}
void
wtls_rec_delete_record (wtls_record_t *rec)
{
if (rec) {
DEALLOC (&(rec->fragment));
OSConnectorFree (rec);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -