/* P_hash as described in WAP WTLS section 11.3.2 */
Octstr *wtls_P_hash(Octstr * secret, Octstr * seed, int byteLength,
          WTLSMachine * wtls_machine)
{
	Octstr *a;
	Octstr *aPrev;
	Octstr *aPlusSeed;
	Octstr *hashTemp;
	Octstr *hashedData;

	hashedData = octstr_create("");
				
	/* start with A(1) = HMAC_hash(secret, seed) */
	aPrev = octstr_duplicate(seed);
	do {
		/* A(i) */
      a = wtls_hmac_hash(secret, aPrev, SHA_80);
		aPlusSeed = octstr_cat(a, seed);
		/* HMAC */
      hashTemp = wtls_hmac_hash(secret, aPlusSeed, SHA_80);
      octstr_destroy(aPlusSeed);
		octstr_append(hashedData, hashTemp);
		octstr_destroy(hashTemp);
		/* Update a(i-1) */
		octstr_destroy(aPrev);
		aPrev = a;
   } while (octstr_len(hashedData) < byteLength);
	
   octstr_destroy(aPrev);
   return (hashedData);
}
/* Pseudo Random Function (PRF) as described in WAP WTLS section 11.3.2 */
Octstr *wtls_calculate_prf(Octstr * secret, Octstr * label, Octstr * seed,
            int byteLength, WTLSMachine * wtls_machine)
{
   Octstr *returnOctstr;
    	Octstr *labelPlusSeed;

    	/* Create label + seed */
		labelPlusSeed = octstr_cat(label, seed);
		
		/* PRF(secret, label, seed) = P_hash(secret, label + seed) */
   returnOctstr = wtls_P_hash(secret, labelPlusSeed, byteLength,
               wtls_machine);
		
    	/* Return the first nbytes of the hashed data */
		octstr_truncate(returnOctstr, byteLength);
		 
   octstr_destroy(labelPlusSeed);
   return (returnOctstr);
}
Example #3
0
/* This function will pack a list of WTLS PDUs into a single Octstr, and return
   that Octstr. */
Octstr* wtls_pack_payloadlist (List* payloadlist) {

        Octstr *returnData=0, *tempData1=0, *tempData2 = 0;
        wtls_Payload* retrievedPDU;
        
        /* Assert that our payloadlist is not NULL */
        gw_assert (payloadlist != NULL);

        /* Initialise our return Octstr */
        returnData = octstr_create("");
        
        /* While there are PDUs remaining in our list */
        while (gwlist_len(payloadlist) > 0) {                
                /* Retrieve the next payload from the payloadlist */
                retrievedPDU = (wtls_Payload*) gwlist_extract_first (payloadlist);

                /* Pack the PDU */
                tempData2 = wtls_payload_pack(retrievedPDU);

                /* Shift the current stuff in returnData to a temporary pointer */
                tempData1 = returnData;
                
                /* Tack it onto our Octstr */
                returnData = octstr_cat(tempData1, tempData2);

                /* And now, we can get rid of both tempData1 and tempData2 */
                octstr_destroy (tempData1);
                octstr_destroy (tempData2);                
        }
        
        /* Is the Octstr we finish with of length > 0? */
        if (octstr_len(returnData) > 0) {        
                /* Return the Octstr */
                return returnData;
        }
        
        /* Otherwise, return NULL */
        return NULL;
}
Example #4
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);
}