Exemplo n.º 1
0
int pack_item(tlv_t * item, void * outbuf, uint32_t * outsize)
{
	int ret = 0;

	if ((NULL == item) || (NULL == outbuf) || (NULL == outsize)) {
		return -1;
	}

	switch (item->type) {
		case TLV_TYPE_INT8:
		case TLV_TYPE_UINT8:
			ret = pack_int8((uint8_t *)(item->value), outbuf, outsize);
			break;
		case TLV_TYPE_INT16:
		case TLV_TYPE_UINT16:
			ret = pack_int16((uint16_t *)(item->value), outbuf, outsize);
			break;
		case TLV_TYPE_INT32:
		case TLV_TYPE_UINT32:
			ret = pack_int32((uint32_t *)(item->value), outbuf, outsize);
			break;
		case TLV_TYPE_BYTES:
			ret = pack_bytes(item->value, item->length, outbuf, outsize);
			break;
		case TLV_TYPE_MSG:
			ret = msg_pack((message_t *)(item->value), outbuf, outsize);
			break;
		default:
			ret = -1;
			break;
	}

	return ret;
}
Exemplo n.º 2
0
Octstr *wtls_payload_pack(wtls_Payload *payload) {
        Octstr *data;
        long bitpos, charpos;
        long messageSizePos, sizepos;
        /* Used for length calculations */
        int size;
        
        /* We rely on octstr_set_bits to lengthen our octstr as needed. */
        data = octstr_create("");
        bitpos = 0;
        charpos = 0;
        sizepos = 0;
        
        /* the record field length flag - always present*/
        octstr_set_bits(data, bitpos, 1, 1);
        bitpos += 1;
        /* the sequence number flag */
        octstr_set_bits(data, bitpos, 1, payload->seqnum);
        bitpos += 1;
        /* the cipher usage flag */
        octstr_set_bits(data, bitpos, 1, payload->cipher);
        bitpos += 1;
        /* the reserved bit */
        octstr_set_bits(data, bitpos, 1, payload->reserved);
        bitpos += 1;

        /* set the message type */
        octstr_set_bits(data, bitpos, 4, payload->type);
        bitpos += 4;
        charpos += 1;

        /* set the sequence number if present */
        if(payload->seqnum) {
                charpos = pack_int16(data, charpos, payload->seqnum);
        }

        /* set the WTLS length  */
        charpos = pack_int16(data, charpos, payload->rlen);
        
        /* append the data from the wtls_PDU */
        octstr_insert(data, payload->data, octstr_len(data)); 
        
        return data;
}
Exemplo n.º 3
0
int stlink2_write_word(programmer_t *pgm, unsigned int word, unsigned int start) {
	unsigned char buf[4], start2[2];
	pack_int16(start, start2);
	stlink2_cmd(pgm, 0xf40a, 8,
			0x00, 0x02,
			0x00, 0x00,
			HI(start), LO(start),
			HI(word), LO(word));
	usleep(2000);
	return(stlink2_get_status(pgm)); // Should be '1'
}
Exemplo n.º 4
0
int stlink2_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start) {
	unsigned char buf[4], start2[2];
	pack_int16(start, start2);
	stlink2_cmd(pgm, 0xf40a, 7,
			0x00, 0x01,
			0x00, 0x00,
			HI(start), LO(start),
			byte);
	usleep(2000);
	return(stlink2_get_status(pgm)); // Should be '1'
}
Exemplo n.º 5
0
int stlink2_write_and_read_byte(programmer_t *pgm, unsigned char byte, unsigned int start) {
	unsigned char buf[4], start2[2];
	pack_int16(start, start2);
	stlink2_cmd(pgm, 0xf40b, 7,
			0x00, 0x01,
			0x00, 0x00,
			HI(start), LO(start),
			byte);
	usleep(2000);
	stlink2_get_status(pgm);

	stlink2_cmd(pgm, 0xf40c, 0);
	return(msg_recv_int8(pgm));
}
Exemplo n.º 6
0
Arquivo: tlv.c Projeto: linhaoye/Dpst
int 
pack_value (tlv_t *tlv, void *outbuf, uint32_t *out_sz) {
  if (NULL == tlv || NULL == outbuf || NULL == out_sz) {
    return -1;
  }

  int b = 0;

  switch (tlv->type) {

  case TLV_TYPE_INT8:
  case TLV_TYPE_UINT8:
    b = pack_int8((uint8_t*)(tlv->value), outbuf, out_sz);
    break;

  case TLV_TYPE_INT16:
  case TLV_TYPE_UINT16:
    b = pack_int16((uint16_t*)(tlv->value), outbuf, out_sz);
    break;

  case TLV_TYPE_INT32:
  case TLV_TYPE_UINT32:
    b = pack_int32((uint32_t*)(tlv->value), outbuf, out_sz);
    break;

  case TLV_TYPE_BYTES:
    b = pack_bytes(tlv->value, tlv->length, outbuf, out_sz);
    break;

  default:
    b = -1;
    break;
  }

  return b;
}
Exemplo n.º 7
0
/* This function will convert our buffer into a completed GenericBlockCipher */
Octstr *wtls_encrypt(Octstr * buffer, WTLSMachine * wtls_machine,
           int recordType)
{
   Octstr *bufferCopy;
   Octstr *encryptedContent;
   Octstr *contentMac;
   Octstr *tempData;
   char *tempPadding = NULL;
   int paddingLength, macSize, blockLength, bufferLength, refresh;
        int i;

   refresh = 1 << wtls_machine->key_refresh;
   if (!(wtls_machine->server_seq_num % refresh))
      calculate_server_key_block(wtls_machine);
        /* Copy our buffer */
        bufferCopy = octstr_duplicate(buffer);
        
        /* Get the MAC of the content */
        bufferLength  = octstr_len(buffer);

        /* Copy the buffer in preparation for MAC calculation */
        tempData = octstr_create("");
   pack_int16(tempData, 0, wtls_machine->server_seq_num);
        octstr_append_char(tempData, recordType);
        pack_int16(tempData, octstr_len(tempData), bufferLength);        
        octstr_append(tempData, buffer);

        /* Calculate the MAC */
   contentMac =
       wtls_hmac_hash(wtls_machine->server_write_MAC_secret, tempData,
            wtls_machine->mac_algorithm);

        /* Calculate the padding length */
        macSize = hash_table[wtls_machine->mac_algorithm].mac_size;
   blockLength =
       bulk_table[wtls_machine->bulk_cipher_algorithm].block_size;

   paddingLength =
       blockLength - ((bufferLength + macSize + 1) % blockLength);

        /* Append the MAC to the bufferCopy */
   octstr_append(bufferCopy, contentMac);
        
        if (paddingLength > 0) {
                /* Pad with the paddingLength itself paddingLength times. Confused yet? */
                tempPadding = gw_malloc(paddingLength);
      for (i = 0; i < paddingLength; i++) {
                        /* You're probably really spaced out around now...
                           see section 9.2.3.3 for more details... */
                        tempPadding[i] = paddingLength;
                }
                octstr_append_data(bufferCopy, tempPadding, paddingLength);
      gw_free(tempPadding);
        }
        /* Add the length byte */
        octstr_append_char(bufferCopy, paddingLength);                

        /* Encrypt the content */
   switch (wtls_machine->bulk_cipher_algorithm) {
   case NULL_bulk:
      encryptedContent = octstr_duplicate(bufferCopy);
      break;

   case RC5_CBC:
   case RC5_CBC_40:
   case RC5_CBC_56:
      encryptedContent =
          wtls_rc5(bufferCopy, wtls_machine, RC5_ENCRYPT);
      break;

   case DES_CBC:
   case DES_CBC_40:
      encryptedContent =
          wtls_des(bufferCopy, wtls_machine, DES_ENCRYPT);
      break;

   default:
      error(0,
            "wtls_encrypt: Unsupported bulk cipher algorithm (%d).",
            wtls_machine->bulk_cipher_algorithm);
      encryptedContent = NULL;
      break;
   }
   octstr_destroy(bufferCopy);
   octstr_destroy(contentMac);
   octstr_destroy(tempData);
   octstr_destroy(buffer);
   return (encryptedContent);
}
Exemplo n.º 8
0
Octstr *wtls_decrypt(wtls_Payload * payload, WTLSMachine * wtls_machine)
{
   int len, padLen = 0, macSize, recordType, block, refresh;
   Octstr *openText, *MAContent, *tempData, *result;
   char cipher[20], *p;

   if (payload->seqNum && wtls_machine->client_seq_num > payload->seqNum) {
      error(0,
            "Out of sequence packet received (p: %d < %d :w). Dropping datagram.",
            payload->seqNum, wtls_machine->client_seq_num);
      return (NULL);
   } else
      wtls_machine->client_seq_num = payload->seqNum;
   refresh = 1 << wtls_machine->key_refresh;
   if (wtls_machine->last_refresh < 0 || (wtls_machine->last_refresh +
                      refresh <=
                      wtls_machine->client_seq_num))
      calculate_client_key_block(wtls_machine);
   switch (wtls_machine->bulk_cipher_algorithm) {
   case NULL_bulk:
      openText = octstr_duplicate(payload->data);
      break;

   case RC5_CBC:
   case RC5_CBC_40:
   case RC5_CBC_56:
      openText = wtls_rc5(payload->data, wtls_machine, RC5_DECRYPT);
      break;

   case DES_CBC:
   case DES_CBC_40:
      openText = wtls_des(payload->data, wtls_machine, DES_DECRYPT);
      break;

   default:
      cipherName(cipher, wtls_machine->bulk_cipher_algorithm);
      error(0,
            "wtls_decrypt: Unsupported bulk cipher algorithm (%s).",
            cipher);
      return (NULL);
      break;
   }
   /* Verify MAC */
   recordType = 1 << 7;
   recordType |= payload->snMode << 6;
   recordType |= payload->cipher << 5;
   recordType |= payload->reserved << 4;
   recordType |= payload->type;
   len = octstr_len(openText);
   p = octstr_get_cstr(openText);
   block = bulk_table[wtls_machine->bulk_cipher_algorithm].block_size;

   padLen = *(p + len - 1);
   if (padLen >= block || padLen != *(p + len - 2))
      padLen = 0;
   padLen++;
   macSize = hash_table[wtls_machine->mac_algorithm].mac_size;

   tempData = octstr_create("");
   pack_int16(tempData, 0, wtls_machine->client_seq_num);
   octstr_append_char(tempData, recordType);
   pack_int16(tempData, 3, len - macSize - padLen);
   octstr_append_data(tempData, p, len - macSize - padLen);
   MAContent = wtls_hmac_hash(wtls_machine->client_write_MAC_secret,
               tempData, wtls_machine->mac_algorithm);
   if (memcmp(octstr_get_cstr(MAContent), p + len - padLen - macSize,
         macSize)) {
      octstr_destroy(MAContent);
      octstr_destroy(tempData);
      octstr_destroy(openText);
      error(0, "wtls_decrypt: Rejected packet due to bad MAC");
      return (NULL);
   }
   octstr_destroy(MAContent);
   octstr_destroy(tempData);
   result = octstr_create_from_data((char *)p, len - padLen - macSize);
   octstr_destroy(openText);
   return (result);
}
Exemplo n.º 9
0
wtls_Payload *wtls_pdu_pack(wtls_PDU *pdu, WTLSMachine* wtls_machine) {
        Octstr *data, *buffer, *encryptedbuffer;
        wtls_Payload *payload;
        long bitpos, charpos;
        long messageSizePos, sizepos;
        /* Used for length calculations */
        int size, recordType;
        
		/* create the wtls_PDU */
		payload = (wtls_Payload *)gw_malloc(sizeof(wtls_Payload));		
		payload->type = pdu->type;
		payload->reserved = pdu->reserved;
		payload->cipher = pdu->cipher;
		payload->seqnum = pdu->seqnum;
		
        /* We rely on octstr_set_bits to lengthen our octstr as needed. */
        data = octstr_create("");
        buffer = octstr_create("");
        bitpos = 0;
        charpos = 0;
        sizepos = 0;
        
        switch (pdu->type) {
        case ChangeCipher_PDU:
                octstr_append_char(buffer, pdu->u.cc.change);
                charpos += 1;
                break;
        case Alert_PDU:
                octstr_append_char(buffer, pdu->u.alert.level);
                charpos += 1;
                octstr_append_char(buffer, pdu->u.alert.desc);
                charpos += 1;
                charpos = pack_octstr_fixed(buffer, charpos, pdu->u.alert.chksum);
                charpos += 1;
                break;  
        case Handshake_PDU:
                octstr_append_char(buffer, pdu->u.handshake.msg_type);
                charpos += 1;
                /* Save the location of the message size */
                messageSizePos = charpos;
                charpos = pack_int16 (buffer, charpos, pdu->u.handshake.length);
                switch (pdu->u.handshake.msg_type) {
                case hello_request:
                        break;
                case client_hello:
                        octstr_append_char(buffer, pdu->u.handshake.client_hello->clientversion);
                        charpos += 1;
                        charpos = pack_random(buffer, charpos, pdu->u.handshake.client_hello->random);
                        octstr_append_char(buffer, octstr_len(
                                pdu->u.handshake.client_hello->session_id));
                        charpos += 1;
                        charpos = pack_octstr(buffer, charpos, pdu->u.handshake.client_hello->session_id);

                        /* pack the list of keys */
                        charpos = pack_key_list(buffer, charpos,
                                                pdu->u.handshake.client_hello->client_key_ids);
                        charpos = pack_key_list(buffer, charpos,
                                                pdu->u.handshake.client_hello->trusted_key_ids);

                        /* pack the list of CipherSuites */
                        charpos = pack_ciphersuite_list(buffer, charpos,
                                                        pdu->u.handshake.client_hello->ciphersuites);

                        /* CompressionMethods */
                        charpos = pack_compression_method_list(buffer, charpos,
                                                               pdu->u.handshake.client_hello->comp_methods);

                        octstr_append_char(buffer, pdu->u.handshake.client_hello->snmode);
                        charpos += 1;
                        octstr_append_char(buffer, pdu->u.handshake.client_hello->krefresh);
                        charpos += 1;
                        break;
                case server_hello:
                        octstr_append_char(buffer, pdu->u.handshake.server_hello->serverversion);
                        charpos += 1;
                        charpos = pack_random(buffer,  charpos, pdu->u.handshake.server_hello->random);
                        charpos = pack_octstr(buffer, charpos, pdu->u.handshake.server_hello->session_id);
                        charpos += 1;
                        octstr_append_char(buffer, pdu->u.handshake.server_hello->
                                           client_key_id);
                        charpos += 1;
                        /* CypherSuite */
                        octstr_append_char(buffer, pdu->u.handshake.server_hello->
                                           ciphersuite->bulk_cipher_algo);
                        charpos += 1;
                        octstr_append_char(buffer, pdu->u.handshake.server_hello->
                                           ciphersuite->mac_algo);
                        charpos += 1;

                        /* CompressionMethod */
                        octstr_append_char(buffer, pdu->u.handshake.server_hello->comp_method);
                        charpos += 1;

                        octstr_append_char(buffer, pdu->u.handshake.server_hello->snmode);
                        charpos += 1;
                        octstr_append_char(buffer, pdu->u.handshake.server_hello->krefresh);
                        charpos += 1;

                        break;
                case certificate:
                        octstr_append_char(buffer, pdu->u.handshake.certificate->certificateformat);
                        charpos += 1;
                        switch (pdu->u.handshake.certificate->certificateformat) {
                        case WTLSCert:
                                charpos = pack_wtls_certificate(buffer, charpos, pdu->u.handshake.certificate->wtls_certificate);
                                break;
                        case X509Cert:
                                charpos = pack_octstr16(buffer, charpos, pdu->u.handshake.certificate->x509_certificate);
                                break;
                        case X968Cert:
                                charpos = pack_octstr16(buffer, charpos, pdu->u.handshake.certificate->x968_certificate);
                                break;
                        }
                        break;
                case server_key_exchange:
			            debug("wtls: ", 0,"Packing ServerKeyExchange");
                        /* pack the ParameterSpecifier */
                        charpos = pack_param_spec(buffer, charpos, pdu->u.handshake.server_key_exchange->param_spec);

                        switch (client_key_exchange_algo) {
                        case rsa_anon:
                                charpos = pack_rsa_pubkey(buffer, charpos, pdu->u.handshake.server_key_exchange->rsa_params);
                                break;
                        case dh_anon:
                                charpos = pack_dh_pubkey(buffer, charpos, pdu->u.handshake.server_key_exchange->dh_params);
                                break;
                        case ecdh_anon:
                                charpos = pack_ec_pubkey(buffer, charpos, pdu->u.handshake.server_key_exchange->ecdh_params);
                                break;
                        }
                        break;
                case client_key_exchange:
                        switch (client_key_exchange_algo) {
                        case rsa:
                        case rsa_anon:
                                charpos = pack_rsa_encrypted_secret(buffer, charpos, pdu->u.handshake.client_key_exchange->rsa_params);
                                break;
                        case dh_anon:
                                charpos = pack_dh_pubkey(buffer, charpos, pdu->u.handshake.client_key_exchange->dh_anon_params);
                                break;
                        case ecdh_anon:
                        case ecdh_ecdsa:
                                charpos = pack_ec_pubkey(buffer, charpos, pdu->u.handshake.client_key_exchange->ecdh_params);
                                break;
                        }
                        break;
                case server_hello_done:
                        /* empty */
                        break;
				case finished:
						charpos = pack_octstr_fixed(buffer, charpos, pdu->u.handshake.finished->verify_data);
						debug("wtls", 0, "verify_data (in pack)");
						octstr_dump(pdu->u.handshake.finished->verify_data,0 );
						break;
                }
                /* Change the length */
                size = octstr_len(buffer) - messageSizePos - 2;
                debug("wtls_msg.c:length",0,"Setting msg size to : %d",size);
                octstr_set_char(buffer, messageSizePos, (size & 0xFF00) >> 8);
				messageSizePos += 1;
				octstr_set_char(buffer, messageSizePos, (size & 0x00FF));
				
				/* we keep the handshake data to create the Finished PDU */
				octstr_append(wtls_machine->handshake_data, buffer);
                break;                
        case Application_PDU:
                /* application message */
                charpos += pack_octstr(data, charpos, pdu->u.application.data);
                break;
    	default:
                panic(0, "Packing unknown WTLS PDU type %ld", (long) pdu->type);
        }
        
        /* encrypt the buffer if needed */
        if(pdu->cipher) {
				/* the MAC is calculated with the record type so we need it now */
				recordType = 1 << 7; /* length, always present */
				recordType |= pdu->seqnum << 6;
				recordType |= pdu->cipher << 5;
				recordType |= pdu->reserved << 4;
				recordType |= pdu->type;
                encryptedbuffer = wtls_encrypt(buffer, wtls_machine, recordType);

                payload->data = encryptedbuffer;
        }
        else {
                payload->data = buffer;
        }

        payload->rlen = octstr_len(payload->data);
        debug("wtls", 0, "Packed PDU Length: %d", payload->rlen);
        
        return payload;
}
Exemplo n.º 10
0
static void exchange_keys(WAPEvent * event, WTLSMachine * wtls_machine)
{
   RSAPublicKey *public_key = NULL;
   Octstr *checking_data = NULL;

   /* The Wap PDUs we have to dispatch */
   wtls_PDU *changeCipherSpecPDU;
   wtls_PDU *finishedPDU;

   /* The PDUs we have to process */
   wtls_Payload *tempPayload;
   wtls_PDU *clientKeyXchgPDU;
   wtls_PDU *changeCipherSpec_incoming_PDU;
   wtls_PDU *finished_incoming_PDU;

   /* For decrypting/encrypting data */
   Octstr *concatenatedRandoms = NULL;
   Octstr *encryptedData = NULL;
   Octstr *decryptedData = NULL;
   Octstr *labelVerify = NULL;
   Octstr *labelMaster = NULL;

   /* Process the incoming event : ClientKeyExchange */
   tempPayload =
       (wtls_Payload *) gwlist_search(event->u.T_Unitdata_Ind.pdu_list,
                  (void *)client_key_exchange,
                  match_handshake_type);

   if (!tempPayload) {
      error(0, "Missing client_key_exchange. Aborting...");
      fatalAlert(event, unexpected_message);
      return;
   }

   /* Keep the data so we can send it back */
   octstr_insert(wtls_machine->handshake_data, tempPayload->data,
            octstr_len(wtls_machine->handshake_data));

   clientKeyXchgPDU = wtls_pdu_unpack(tempPayload, wtls_machine);
   wtls_pdu_dump(clientKeyXchgPDU, 0);

   /* Decrypt the client key exchange PDU */
   encryptedData =
       clientKeyXchgPDU->u.handshake.client_key_exchange->rsa_params->
       encrypted_secret;
   decryptedData =
       wtls_decrypt_key(wtls_machine->key_algorithm, encryptedData);

   if (!decryptedData) {
      error(0,
            "Key Exchange failed. Couldn't decrypt client's secret (%d)."
            " Aborting...", wtls_machine->key_algorithm);
      wtls_pdu_destroy(clientKeyXchgPDU);
      fatalAlert(event, decryption_failed);
      return;
   }
   public_key = wtls_get_rsapublickey();
   pack_int16(decryptedData, octstr_len(decryptedData),
         octstr_len(public_key->rsa_exponent));
   octstr_insert(decryptedData, public_key->rsa_exponent,
            octstr_len(decryptedData));
   pack_int16(decryptedData, octstr_len(decryptedData),
         octstr_len(public_key->rsa_modulus));
   octstr_insert(decryptedData, public_key->rsa_modulus,
            octstr_len(decryptedData));

   /* Concatenate our random data */
   concatenatedRandoms = octstr_cat(wtls_machine->client_random,
                wtls_machine->server_random);

   /* Generate our master secret */
   labelMaster = octstr_create("master secret");
   wtls_machine->master_secret = wtls_calculate_prf(decryptedData,
                      labelMaster,
                      concatenatedRandoms,
                      20, wtls_machine);

   /* Process the incoming event : ChangeCipherSpec */
   tempPayload =
       (wtls_Payload *) gwlist_search(event->u.T_Unitdata_Ind.pdu_list,
                  (void *)ChangeCipher_PDU,
                  match_pdu_type);

   if (!tempPayload) {
      error(0, "Missing change_cipher. Aborting...");
      octstr_destroy(labelMaster);
      octstr_destroy(concatenatedRandoms);
      destroy_rsa_pubkey(public_key);
      octstr_destroy(decryptedData);
      octstr_destroy(encryptedData);
      fatalAlert(event, unexpected_message);
      return;
   }

   changeCipherSpec_incoming_PDU = wtls_pdu_unpack(tempPayload,
                     wtls_machine);
   octstr_dump(wtls_machine->client_write_MAC_secret, 0);

   wtls_pdu_dump(changeCipherSpec_incoming_PDU, 0);

   if (changeCipherSpec_incoming_PDU->u.cc.change == 1) {
      debug("wtls", 0, "Need to decrypt the PDUs from now on...");
      wtls_decrypt_pdu_list(wtls_machine,
                  event->u.T_Unitdata_Ind.pdu_list);
   }

   /* Process the incoming event : Finished */
   tempPayload =
       (wtls_Payload *) gwlist_search(event->u.T_Unitdata_Ind.pdu_list,
                  (void *)finished,
                  match_handshake_type);
   if (!tempPayload) {
      error(0, "Failed to decrypt finished PDU. Aborting...");
      wtls_pdu_destroy(changeCipherSpec_incoming_PDU);
      octstr_destroy(labelMaster);
      octstr_destroy(concatenatedRandoms);
      destroy_rsa_pubkey(public_key);
      octstr_destroy(decryptedData);
      octstr_destroy(encryptedData);
      fatalAlert(event, decrypt_error);
      return;
   }
   finished_incoming_PDU = wtls_pdu_unpack(tempPayload, wtls_machine);
   debug("wtls", 0, "Client Finished PDU:");
   wtls_pdu_dump(finished_incoming_PDU, 0);

   /* Check the verify_data */
   labelVerify = octstr_create("client finished");
   checking_data = wtls_calculate_prf(wtls_machine->master_secret,
                  labelVerify,
                  (Octstr *) wtls_hash(wtls_machine->
                        handshake_data,
                        wtls_machine),
                  12, wtls_machine);

   if (octstr_compare
       (finished_incoming_PDU->u.handshake.finished->verify_data,
        checking_data) == 0) {
      wtls_machine->encrypted = 1;
      debug("wtls", 0, "DATA VERIFICATION OK");
   }

   /* Keep the data so we can send it back in the next message
    * octstr_insert(wtls_machine->handshake_data, tempPayload->data,
    * octstr_len(wtls_machine->handshake_data));
    */
   // temporary fix
   octstr_truncate(tempPayload->data, 15);
   octstr_insert(wtls_machine->handshake_data, tempPayload->data,
            octstr_len(wtls_machine->handshake_data));

   /* Create a new PDU List containing a ChangeCipherSpec and a Finished */
   changeCipherSpecPDU = wtls_pdu_create(ChangeCipher_PDU);
   changeCipherSpecPDU->u.cc.change = 1;
   changeCipherSpecPDU->rlen = 1;
   changeCipherSpecPDU->snMode =
       wtls_machine->sequence_number_mode ? 1 : 0;

   /* Generate our verify data */
   finishedPDU = wtls_pdu_create(Handshake_PDU);
   finishedPDU->u.handshake.msg_type = finished;
   finishedPDU->cipher = 1;
   finishedPDU->rlen = 1;
   finishedPDU->snMode = wtls_machine->sequence_number_mode ? 1 : 0;;
   finishedPDU->u.handshake.finished = gw_malloc(sizeof(Finished));

   octstr_destroy(labelVerify);
   labelVerify = octstr_create("server finished");

   finishedPDU->u.handshake.finished->verify_data = wtls_calculate_prf
       (wtls_machine->master_secret, labelVerify, (Octstr *) wtls_hash
        (wtls_machine->handshake_data, wtls_machine), 12, wtls_machine);

   /* Reset the accumulated Handshake data */
   octstr_destroy(wtls_machine->handshake_data);
   wtls_machine->handshake_data = octstr_create("");

   /* Add the pdus to our list */
   add_pdu(wtls_machine, changeCipherSpecPDU);
   add_pdu(wtls_machine, finishedPDU);

   /* Send it off */
   send_queuedpdus(wtls_machine);

   octstr_destroy(labelMaster);
   octstr_destroy(labelVerify);
   octstr_destroy(decryptedData);
   octstr_destroy(encryptedData);
   octstr_destroy(concatenatedRandoms);

   wtls_pdu_destroy(finished_incoming_PDU);
   wtls_pdu_destroy(changeCipherSpec_incoming_PDU);

   wtls_pdu_destroy(finishedPDU);
   wtls_pdu_destroy(changeCipherSpecPDU);

   octstr_destroy(checking_data);
   destroy_rsa_pubkey(public_key);
}