📄 record.c
字号:
wtls_log_record (rec, LOG_OUTBOUND);
#endif
if (rec->rec_type & RECTYPE_USE_CS) {
UINT16 s;
/* Time for key refresh? */
s = (~0 << conn->write.key_refresh_rate) & (rec->seqnum);
if (s != conn->write.last_refresh) {
conn->write.last_refresh = s;
return RET_KEY_REFRESH;
}
return RET_ENCRYPT_RECORD;
}
return RET_OK;
}
/*
* Create an application data record, for immediate transmission.
*/
SDL_Integer
wtls_rec_prepare_data_record (void *connptr, void *recptr)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec = (wtls_record_t *)recptr;;
/* Always use a length field. */
rec->rec_type |= RECTYPE_LENGTH_FIELD;
rec->seqnum = conn->write.seqnum++;
if (conn->write.use_cipher_spec) {
rec->rec_type |= RECTYPE_USE_CS;
}
if (conn->write.seqnum_mode == SEQNUMMODE_EXPLICIT) {
rec->rec_type |= RECTYPE_SEQNUM;
}
#ifdef LOG_WTLS
wtls_log_msg (0, "\n--------CREATING OUTBOUND RECORD--------\n");
wtls_log_record (rec, LOG_OUTBOUND);
#endif
if (rec->rec_type & RECTYPE_USE_CS) {
UINT16 s;
/* Time for key refresh? */
s = (~0 << conn->write.key_refresh_rate) & (rec->seqnum);
if (s != conn->write.last_refresh) {
conn->write.last_refresh = s;
return RET_KEY_REFRESH;
}
return RET_ENCRYPT_RECORD;
}
return RET_OK;
}
/*
* Encode a record in a SDU.
*/
INT16
wtls_rec_create_SDU (void *connptr, void *recptr, TDUnitdataReqType *data_req)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec = (wtls_record_t *)recptr;
wap_cvt_t cvt_obj;
BYTE *buf;
UINT16 buflen;
#ifdef LOG_WTLS
wtls_log_msg (0, "\n-------SENDING SDU--------\n");
wtls_log_msg (0, "SDU[ =>\n");
wtls_log_record_brief (rec);
wtls_log_msg (0, "]\n");
#endif
wap_cvt_init (&cvt_obj, WAP_CVT_ENCODE_SIZE, NULL, 0);
if (!wtls_cvt_record (&cvt_obj, rec)) {
wtls_err_set (ERR_INTERNAL, ERR_ENCODING,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
wtls_rec_delete_record (rec);
return -1;
}
buflen = (UINT16)cvt_obj.pos;
buf = NEWARRAY (BYTE, buflen);
if (buf == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
}
wap_cvt_init (&cvt_obj, WAP_CVT_ENCODE, buf, buflen);
if (!wtls_cvt_record (&cvt_obj, rec)) {
wtls_err_set (ERR_INTERNAL, ERR_ENCODING,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
wtls_rec_delete_record (rec);
DEALLOC (&buf);
return -1;
}
/* Allocate a PDU buffer. */
data_req->UserData = pdubuf_newFromData (buflen, buf);
if (data_req->UserData == NULL) {
wtls_rec_delete_record (rec);
DEALLOC (&buf);
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
pdubuf_setLength (data_req->UserData, buflen);
/* Copy addresses from the connection state. */
yAssF_AddressType (data_req->SourceAddress, conn->client_addr, XASS);
yAssF_AddressType (data_req->DestinationAddress, conn->server_addr, XASS);
conn->write_cksum [conn->num_cksums++ % 4] =
wtls_alert_compute_checksum (buf, buflen);
wtls_rec_delete_record (rec);
return RET_OK;
}
/*
* Create a SDU holding the stored outbound handshake records,
* plus an application data record, for immediate sending.
*/
SDL_Integer
wtls_rec_create_data_and_buffer_SDU (void *connptr,
void *recptr,
TDUnitdataReqType *data_req)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec = (wtls_record_t *)recptr;
wtls_record_t *prec;
wap_cvt_t cvt_obj;
UINT16 totlen = 0;
UINT16 lastlen;
BYTE *lastpos;
/* Compute length of all saved outbound records. */
totlen = rec->length + RECORD_HEADER_SIZE (rec);
for (prec = conn->out_records; prec != NULL; prec = prec->next) {
totlen += prec->length + RECORD_HEADER_SIZE (prec);
}
/* Allocate new PDU buffer. */
data_req->UserData = pdubuf_new (totlen);
if (data_req->UserData == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
0, ALERT_LEVEL_FATAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
pdubuf_setLength (data_req->UserData, totlen);
/* Copy the outgoing data to the PDU buffer. */
#ifdef LOG_WTLS
wtls_log_msg (0, "\n--------SENDING SDU--------\n");
wtls_log_msg (0, "SDU[ =>\n");
#endif
wap_cvt_init (&cvt_obj, WAP_CVT_ENCODE,
pdubuf_getStart (data_req->UserData), totlen);
for (prec = conn->out_records; prec != NULL; prec = prec->next) {
lastpos = cvt_obj.data + cvt_obj.pos;
if (!wtls_cvt_record (&cvt_obj, prec)) {
wtls_err_set (ERR_INTERNAL, ERR_ENCODING,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
lastlen = (cvt_obj.data + cvt_obj.pos) - lastpos;
#ifdef LOG_WTLS
wtls_log_record_brief (prec);
#endif
}
if (!wtls_cvt_record (&cvt_obj, rec)) {
wtls_err_set (ERR_INTERNAL, ERR_ENCODING,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
#ifdef LOG_WTLS
wtls_log_record_brief (rec);
wtls_log_msg (0, "]\n");
#endif
wtls_rec_delete_record (rec);
/* Copy addresses from the connection state. */
yAssF_AddressType (data_req->SourceAddress, conn->client_addr, XASS);
yAssF_AddressType (data_req->DestinationAddress, conn->server_addr, XASS);
conn->write_cksum [conn->num_cksums++ % 4] =
wtls_alert_compute_checksum (lastpos, lastlen);
return RET_OK;
}
/*
* Create a SDU holding the stored outbound handshake records,
* for immediate sending.
*/
INT16
wtls_rec_create_buffer_SDU (void *connptr, TDUnitdataReqType *data_req)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec;
wap_cvt_t cvt_obj;
UINT16 totlen;
UINT16 lastlen;
BYTE *lastpos;
/* Should we allow this, and just return? Then, what should be sent? */
if (conn->out_records == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_MISSING_RECORD_BUFFER,
1, ALERT_LEVEL_FATAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
/* Compute length of all saved outbound records. */
totlen = 0;
for (rec = conn->out_records; rec != NULL; rec = rec->next) {
totlen += rec->length + RECORD_HEADER_SIZE (rec);
}
/* Allocate a PDU buffer. */
data_req->UserData = pdubuf_new (totlen);
if (data_req->UserData == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
1, ALERT_LEVEL_FATAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
pdubuf_setLength (data_req->UserData, totlen);
/* Copy the outgoing data to the PDU buffer. */
#ifdef LOG_WTLS
wtls_log_msg (0, "\n--------SENDING SDU--------\n");
wtls_log_msg (0, "SDU[ =>\n");
#endif
wap_cvt_init (&cvt_obj, WAP_CVT_ENCODE,
pdubuf_getStart (data_req->UserData), totlen);
for (rec = conn->out_records; rec != NULL; rec = rec->next) {
lastpos = cvt_obj.data + cvt_obj.pos;
if (!wtls_cvt_record (&cvt_obj, rec)) {
wtls_err_set (ERR_INTERNAL, ERR_ENCODING,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
lastlen = (cvt_obj.data + cvt_obj.pos) - lastpos;
#ifdef LOG_WTLS
wtls_log_record_brief (rec);
#endif
}
#ifdef LOG_WTLS
wtls_log_msg (0, "]\n");
#endif
/* Copy addresses from the connection state. */
yAssF_AddressType (data_req->SourceAddress, conn->client_addr, XASS);
yAssF_AddressType (data_req->DestinationAddress, conn->server_addr, XASS);
/* Compute Alert checksum. */
conn->write_cksum [conn->num_cksums++ % 4] =
wtls_alert_compute_checksum (lastpos, lastlen);
return RET_OK;
}
/*
* Remove the stored outbound handshake records.
*/
void
wtls_rec_clear_buffer (void *connptr)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_rec_list_delete (&(conn->out_records));
}
void
wtls_rec_list_delete (wtls_record_t **rlist)
{
wtls_record_t *rec;
while (*rlist != NULL) {
rec = *rlist;
*rlist = rec->next;
DEALLOC (&rec->fragment);
DEALLOC (&rec);
}
}
/**********************************************************
*
* ROUTINES FOR INCOMING RECORDS
*
**********************************************************/
/*
* The WTLS protocol states that several records may be sent in
* one SDU. This packaging of records ought to be transparent to
* the layers above the record layer. However, since Alert messages
* need to include a checksum computed on the last record sent
* by the other end, we have to identify and process each record
* in the SDU we receive before we start passing the records to
* the layers above. Hence the routine SplitIncomingSDU below.
*
* During the initial processing of the records in a SDU we perform
* a number of checks, to decide whether to accept the record.
* Only records that pass those checks will be passed to higher
* layers, and also will affect the sequence numbers and Alert
* checksums. However, all the records will be extracted and
* stored in a list of incoming, undelivered records.
*
* In the next pass, when the records are passed to the layers above,
* further checks may yield new errors. For example, decryption
* is carried out at this stage and may give erroneous results.
*/
/*
* Handling of sequence numbers.
* The current value of the read state's seqNum value is one
* greater than the largest incoming sequence number we have seen.
* Hence, initially, the value is 0.
*
* The current value of the write state's seqNum value, is the
* sequence number we should use in the next Record we send.
* Hence, here too, the value is initally 0.
*
* We use a sliding window of size 32, and keep track of which
* sequence numbers we have seen with the help of a bit mask
* of 32 bits. The rightmost bit in the bit mask represents
* the largest sequence number we have seen. Each bit in the mask
* that is set, means that the sequence number has been seen.
* For example, if the read state's seqNum value is 118, then
* the bits in the mask represent the sequence numbers 86..117.
*/
#define WINDOW_SIZE 32
/*
* Check if a given sequence number is acceptable, i.e.,
* is either larger than the largest seen so far,
* or is smaller but within the window limits and is not marked
* as having been seen. Does NOT update the window or mask.
*/
static INT16
wtls_rec_check_seqnum (UINT16 seqnum, wtls_connection_t *conn)
{
UINT16 diff;
if (seqnum >= conn->read.seqnum) { /* Larger than largest so far is OK */
return RET_OK;
}
diff = conn->read.seqnum - seqnum;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -