/* 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); }
/* 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; }
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); }