📄 record.c
字号:
/*
* Copyright (C) Ericsson Mobile Communications AB, 2000.
* Licensed to AU-System AB.
* All rights reserved.
*
* This software is covered by the license agreement between
* the end user and AU-System AB, and may be used and copied
* only in accordance with the terms of the said agreement.
*
* Neither Ericsson Mobile Communications AB nor AU-System AB
* assumes any responsibility or liability for any errors or inaccuracies in
* this software, or any consequential, incidental or indirect damage arising
* out of the use of the Generic WAP Client software.
*/
/*
* record.c
*
* Created by Anders Edenbrandt, Fri May 21 08:41:32 1999.
*
* Revision history:
* 001012, AED: Changed how records are logged.
*
*
* This file implements the Record layer in WTLS.
*
*/
#include "wtlsdef.h"
#define RECORD_HEADER_SIZE(rec) (1 + \
(((rec)->rec_type & RECTYPE_SEQNUM) ? 2 : 0) + \
(((rec)->rec_type & RECTYPE_LENGTH_FIELD) ? 2 : 0))
/*
* Initialize the record layer at startup.
* Presently, there is nothing in particular we have to do...??
*/
void
wtls_rec_init (void)
{
}
/*
* Install the pending state as the current write state.
*/
INT16
wtls_rec_install_pending_write (void *connptr)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
conn->h_state->abortable = 0;
wtls_pending_state_install (&(conn->write), &(conn->h_state->pending));
conn->write.last_refresh = 0;
return RET_OK;
}
/*
* Install the pending state as the current read state.
*/
INT16
wtls_rec_install_pending_read (void *connptr)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
conn->h_state->abortable = 0;
wtls_pending_state_install (&(conn->read), &(conn->h_state->pending));
conn->mask = 0;
conn->read.last_refresh = 0;
return RET_OK;
}
/*
* Compress, compute MAC and encrypt a record.
* On input, the message part to encrypt is held in rec->fragment.
* On output, rec->fragment is replaced by the encrypted version,
* and the old fragment is deallocated.
*/
INT16
wtls_rec_encrypt_record (void *connptr, void *recptr)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec = (wtls_record_t *)recptr;
wtls_connection_state *cstate = &(conn->write);
BYTE md[MAX_HASH_MAC_SIZE];
BYTE *buf;
UINT16 buflen;
/* Compress */
if (cstate->cobj.compression_alg != COMPRESS_NULL) {
/* Currently we have no compression algorithms. */
}
/* Compute MAC. */
if (cstate->cobj.mac_size > 0) {
if (wtls_crypto_MAC (&(cstate->cobj), cstate->mac_secret,
rec->fragment, rec->length,
rec->seqnum, rec->rec_type, md) < 0) {
wtls_err_set (ERR_INTERNAL, ERR_PROGRAMMING_ERROR,
0, ALERT_LEVEL_FATAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
}
/* Encrypt: */
if (cstate->cobj.type == CIPHER_TYPE_BLOCK) {
BYTE iv1[MAX_IV_SIZE];
UINT16 i, len;
UINT8 paddinglen;
BYTE padding[8];
/* Fix the per-record IV (described in section 11.2) */
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);
}
/* Add padding, to make the length a multiple of the block length. */
/* The padding algorithm is described in section 9.2.3.3. */
len = rec->length + cstate->cobj.mac_size + 1;
paddinglen = cstate->cobj.block_size - (len % cstate->cobj.block_size);
if (paddinglen == cstate->cobj.block_size) {
paddinglen = 0;
}
for (i = 0; i <= paddinglen; i++) {
padding[i] = paddinglen;
}
/* Now, the encryption. The result is placed in a new buffer,
* that will replace the current fragment. */
buflen = rec->length + cstate->cobj.mac_size + 1 + paddinglen;
buf = NEWARRAY (BYTE, buflen);
if (buf == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
0, ALERT_LEVEL_FATAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
B_COPYSTRINGN (buf, rec->fragment, rec->length);
B_COPYSTRINGN (buf + rec->length, md, cstate->cobj.mac_size);
B_COPYSTRINGN (buf + rec->length + cstate->cobj.mac_size,
padding, paddinglen + 1);
if (wtls_crypto_encrypt (&(cstate->cobj),
cstate->encryption_key, iv1,
buf, buflen,
buf) < 0) {
DEALLOC (&buf);
wtls_err_set (ERR_INTERNAL, ERR_PROGRAMMING_ERROR,
0, ALERT_LEVEL_FATAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
DEALLOC (&(rec->fragment));
rec->fragment = buf;
rec->length = buflen;
}
else {
/* Currently we have no stream ciphers except the NULL alg. */
if (cstate->cobj.mac_size > 0) {
buflen = rec->length + cstate->cobj.mac_size;
buf = NEWARRAY (BYTE, buflen);
if (buf == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
0, ALERT_LEVEL_FATAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
B_COPYSTRINGN (buf, rec->fragment, rec->length);
B_COPYSTRINGN (buf + rec->length, md, cstate->cobj.mac_size);
DEALLOC (&(rec->fragment));
rec->fragment = buf;
rec->length = buflen;
}
}
return RET_OK;
}
/*
* With each connection we have a list of records where we store
* handshake messages to be sent at a later time.
* The records in this list are transmitted by calling the routine
* CreateBufferSDU. They can be resent, by calling CreateBufferSDU
* several times. In addition, an outgoing data record may be sent
* with the records in the table prepended to the data record,
* and all of the records sent in one SDU. To do this, one calls
* the routine CreateDataAndBufferSDU.
*/
void
wtls_rec_append_record (void *connptr, void *recptr)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec = (wtls_record_t *)recptr;
wtls_rec_list_append (rec, &(conn->out_records));
}
/*
* Create a handshake message record, to be appended to the buffer.
*/
SDL_Integer
wtls_rec_create_handshake_record (void *connptr,
void *buf, SDL_Natural buflen,
void **pprec)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec;
rec = NEWARRAY (wtls_record_t, 1);
if (rec == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
1, ALERT_LEVEL_FATAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
/* Always use a length field. */
rec->rec_type = CONTENT_TYPE_HANDSHAKE | RECTYPE_LENGTH_FIELD;
rec->seqnum = conn->write.seqnum++;
rec->fragment = buf;
rec->length = (UINT16)buflen;
if (conn->write.use_cipher_spec) {
rec->rec_type |= RECTYPE_USE_CS;
}
/* Sequence numbers MUST be used in handshake messages.
* (WTLS spec. 9.2.3.1) */
rec->rec_type |= RECTYPE_SEQNUM;
*pprec = rec;
#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;
}
/*
* Create a CCS record, for immediate transmission.
*/
INT16
wtls_rec_create_CCS_record (void *connptr, void **pprec)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec;
rec = NEWARRAY (wtls_record_t, 1);
if (rec == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
1, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
}
/* Always use a length field. */
rec->rec_type = CONTENT_TYPE_CCS | RECTYPE_LENGTH_FIELD;
rec->seqnum = conn->write.seqnum++;
rec->length = 1;
rec->fragment = NEWARRAY (BYTE, 1);
rec->fragment[0] = 1;
if (conn->write.use_cipher_spec) {
rec->rec_type |= RECTYPE_USE_CS;
}
/* Sequence numbers MUST be used in handshake messages,
* (WTLS spec. 9.2.3.1), but is CCS a 'handshake message' in
* this context? Let's hope so... */
rec->rec_type |= RECTYPE_SEQNUM;
*pprec = rec;
#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;
}
/*
* Create an Alert record, for immediate transmission.
*/
INT16
wtls_rec_create_alert_record (void *connptr,
SDL_Integer alert_level, SDL_Integer alert_desc,
void **pprec)
{
wtls_connection_t *conn = (wtls_connection_t *)connptr;
wtls_record_t *rec;
wtls_alert_t alert;
wap_cvt_t cvt_obj;
rec = NEWARRAY (wtls_record_t, 1);
if (rec == NULL) {
wtls_err_set (ERR_INTERNAL, ERR_INSUFFICIENT_MEMORY,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
return -1;
}
/* Always use a length field. */
rec->rec_type = CONTENT_TYPE_ALERT | RECTYPE_LENGTH_FIELD;
rec->seqnum = conn->write.seqnum++;
rec->length = 6;
rec->fragment = NEWARRAY (BYTE, 6);
if (conn->write.seqnum_mode == SEQNUMMODE_EXPLICIT) {
rec->rec_type |= RECTYPE_SEQNUM;
}
alert.level = (BYTE)alert_level;
alert.description = (BYTE)alert_desc;
alert.checksum = conn->read_cksum;
if (conn->write.use_cipher_spec &&
(alert.description != ALERT_DESC_NO_CONNECTION) &&
(alert.description != ALERT_DESC_BAD_RECORD_MAC) &&
(alert.description != ALERT_DESC_DECRYPTION_FAILED) &&
(alert.description != ALERT_DESC_RECORD_OVERFLOW) &&
(alert.description != ALERT_DESC_DECOMPRESSION_FAILURE)) {
rec->rec_type |= RECTYPE_USE_CS;
}
wap_cvt_init (&cvt_obj, WAP_CVT_ENCODE, rec->fragment, rec->length);
if (!wtls_cvt_alert (&cvt_obj, &alert)) {
wtls_err_set (ERR_INTERNAL, ERR_ENCODING,
0, ALERT_LEVEL_CRITICAL, ALERT_DESC_INTERNAL_ERROR);
}
*pprec = rec;
#ifdef LOG_WTLS
wtls_log_msg (0, "\n--------CREATING OUTBOUND RECORD--------\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -