⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 record.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -