/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2005 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtls_statesupport.c * * 2001 Nick Clarey, Yann Muller for 3G LAB */ #include "gwlib/gwlib.h" #if (HAVE_WTLS_OPENSSL) #include #ifndef NO_RC5 #include #else #error "your OpenSSL installation lacks RC5 algorithm support" #endif #include "wtls_statesupport.h" #define BLOCKLENGTH 64 #define INNERPAD 0x36 #define OUTERPAD 0x5C extern X509* x509_cert; extern RSA* private_key; extern KeyExchangeSuite client_key_exchange_algo; extern PublicKeyAlgorithm public_key_algo; extern SignatureAlgorithm signature_algo; Octstr* wtls_hmac_hash(Octstr* key, Octstr* data, WTLSMachine* wtls_machine); Octstr* wtls_hash(Octstr* inputData, WTLSMachine* wtls_machine); Octstr* wtls_encrypt_rc5(Octstr* data, WTLSMachine* wtls_machine); Octstr* wtls_decrypt_rc5(Octstr* encryptedData, WTLSMachine* wtls_machine); /* Add here the supported KeyExchangeSuites used by wtls_choose_clientkeyid */ KeyExchangeSuite supportedKeyExSuite[] = { rsa_anon }; Octstr* wtls_decrypt(Octstr* buffer, WTLSMachine* wtls_machine) { return wtls_decrypt_rc5(buffer,wtls_machine); } /* 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* padding; Octstr* tempData; unsigned char* tempPadding; int paddingLength, contentLength, macSize, blockLength, sequenceNumber, bufferLength; int i; /* Copy our buffer */ bufferCopy = octstr_duplicate(buffer); /* Get the MAC of the content */ sequenceNumber = wtls_machine->server_seq_num; bufferLength = octstr_len(buffer); /* Copy the buffer in preparation for MAC calculation */ tempData = octstr_create(""); pack_int16(tempData, 0, sequenceNumber); 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); /* Calculate the padding length */ contentLength = octstr_len(bufferCopy); macSize = hash_table[wtls_machine->mac_algorithm].mac_size; blockLength = bulk_table[wtls_machine->bulk_cipher_algorithm].block_size; paddingLength = (contentLength + 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); } /* Add the length byte */ octstr_append_char(bufferCopy, paddingLength); /* Encrypt the content */ encryptedContent = wtls_encrypt_rc5(bufferCopy,wtls_machine); return encryptedContent; } /* 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, wtls_machine); aPlusSeed = octstr_cat(a, seed); /* HMAC */ hashTemp = wtls_hmac_hash(secret, aPlusSeed, wtls_machine); octstr_append(hashedData, hashTemp); octstr_destroy(hashTemp); /* Update a(i-1) */ octstr_destroy(aPrev); aPrev = a; } while(octstr_len(hashedData) < byteLength); gw_free(aPlusSeed); 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); gw_free(labelPlusSeed); return returnOctstr; } /* MAC calculation */ Octstr* wtls_hmac_hash(Octstr* key, Octstr* data, WTLSMachine* wtls_machine) { static unsigned char final_mac[1024]; unsigned char *mac, *buffer, *keyString; int mac_len, bufferlen, keylen; Octstr *returnOctstr; buffer = octstr_get_cstr(data); bufferlen = octstr_len(data); keyString = octstr_get_cstr(key); keylen = octstr_len(key); mac = final_mac; switch (wtls_machine->mac_algorithm) { case SHA_0: /* no keyed MAC is calculated */ /* So what do we return ? */ break; case SHA_40: case SHA_80: case SHA_NOLIMIT: HMAC(EVP_sha1(), keyString, keylen, buffer, bufferlen, mac, &mac_len); break; case SHA_XOR_40: // dunno yet break; case MD5_40: case MD5_80: case MD5_NOLIMIT: HMAC(EVP_md5(), keyString, keylen, buffer, bufferlen, mac, &mac_len); break; } returnOctstr = octstr_create_from_data(mac, mac_len); } /* Not to be confused with octstr_hash, this applies the currently set hashing algorithm from wtls_machine to the supplied input data, returning a hashed Octstr. If it fails, it will return a NULL pointer */ Octstr* wtls_hash(Octstr* inputData, WTLSMachine* wtls_machine) { int inputDataLength; int outputDataLength; unsigned char* outputDataTemp; unsigned char* inputDataTemp; unsigned char* tempPointer; Octstr* outputData; inputDataLength = octstr_len(inputData); outputDataLength = hash_table[wtls_machine->mac_algorithm].key_size; inputDataTemp = gw_malloc(inputDataLength); outputDataTemp = gw_malloc(outputDataLength); /* Copy the contents of inputData into inputDataTemp, ready for hashing */ tempPointer = octstr_get_cstr(inputData); memcpy((void*) inputDataTemp, (void*)tempPointer, inputDataLength); /* Hash away! */ // Here's where we need to hash on the selected algorithm, not just the SHA-1 algorithm //debug("wtls", 0, "mac algo %d", wtls_machine->mac_algorithm); switch (wtls_machine->mac_algorithm) { case SHA_0: /* no keyed MAC is calculated */ // So what do we return ? break; case SHA_40: case SHA_80: case SHA_NOLIMIT: tempPointer = SHA1(inputDataTemp, inputDataLength, outputDataTemp); break; case SHA_XOR_40: // dunno yet break; case MD5_40: case MD5_80: case MD5_NOLIMIT: tempPointer = MD5(inputDataTemp, inputDataLength, outputDataTemp); break; } if (tempPointer == NULL){ /* Pop out an error */ } /* Get our output data setup */ outputData = octstr_create_from_data(outputDataTemp,outputDataLength); /* some algorithms don't use the full length of H */ octstr_truncate(outputData, hash_table[wtls_machine->mac_algorithm].mac_size); /* Delete our allocated memory */ gw_free(outputDataTemp); gw_free(inputDataTemp); outputDataTemp = NULL; inputDataTemp = NULL; /* Return the outputData */ return outputData; } Octstr* wtls_decrypt_rc5(Octstr* data, WTLSMachine* wtls_machine) { Octstr* encryptedData; Octstr* decryptedData; Octstr* duplicatedIv; unsigned char* output; unsigned char* input; unsigned char* iv; unsigned char* keyData; int keyLen; int ivLen; int dataLen; RC5_32_KEY* key = NULL; ivLen = bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size; duplicatedIv = octstr_duplicate(wtls_machine->client_write_IV); iv = octstr_get_cstr(duplicatedIv); keyLen = bulk_table[wtls_machine->bulk_cipher_algorithm].key_material; keyData = octstr_get_cstr(wtls_machine->client_write_enc_key); dataLen = octstr_len(data); input = octstr_get_cstr(data); key = gw_malloc (sizeof(RC5_32_KEY)); /* Key generation */ RC5_32_set_key(key, keyLen, keyData, RC5_16_ROUNDS); /* Malloc our output */ output = gw_malloc (dataLen); /* Encrypt the string */ debug("wtls_statesupport",0,"About to decrypt: dataLen = %d, iv = %x", dataLen, iv); octstr_dump(data,0); RC5_32_cbc_encrypt(input, output, dataLen, key, iv, RC5_DECRYPT); debug("wtls_statesupport",0,"Decrypted"); decryptedData = octstr_create_from_data(output, dataLen); octstr_dump(decryptedData,0); /* Encrypt it just to test */ gw_free(output); output = NULL; output = gw_malloc (dataLen); /* Ensure that we preserve the iv */ octstr_destroy(duplicatedIv); duplicatedIv = octstr_duplicate(wtls_machine->client_write_IV); iv = octstr_get_cstr(duplicatedIv); octstr_get_many_chars(iv, wtls_machine->client_write_IV,0,ivLen); input = octstr_get_cstr(decryptedData); RC5_32_cbc_encrypt(input, output, dataLen, key, iv, RC5_ENCRYPT); encryptedData = octstr_create_from_data(output, dataLen); gw_free(output); output = NULL; octstr_destroy(duplicatedIv); return decryptedData; } Octstr* wtls_encrypt_rc5(Octstr* data, WTLSMachine* wtls_machine) { Octstr* encryptedData; Octstr* decryptedData; Octstr* duplicatedIv; unsigned char* output; unsigned char* input; unsigned char* iv; unsigned char* keyData; int keyLen; int ivLen; int dataLen; RC5_32_KEY* key = NULL; ivLen = bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size; duplicatedIv = octstr_duplicate(wtls_machine->server_write_IV); iv = octstr_get_cstr(duplicatedIv); keyLen = bulk_table[wtls_machine->bulk_cipher_algorithm].key_material; keyData = octstr_get_cstr(wtls_machine->server_write_enc_key); dataLen = octstr_len(data); input = octstr_get_cstr(data); key = gw_malloc (sizeof(RC5_32_KEY)); /* Key generation */ debug("wtls_statesupport",0,"Key generation"); RC5_32_set_key(key, keyLen, keyData, RC5_16_ROUNDS); /* Malloc our output */ output = gw_malloc (dataLen); /* Encrypt the string */ RC5_32_cbc_encrypt(input, output, dataLen, key, iv, RC5_ENCRYPT); encryptedData = octstr_create_from_data(output, dataLen); /* Decrypt it just to test */ gw_free(output); output = NULL; output = gw_malloc (dataLen); /* Ensure that we preserve the iv */ octstr_destroy(duplicatedIv); duplicatedIv = octstr_duplicate(wtls_machine->server_write_IV); iv = octstr_get_cstr(duplicatedIv); octstr_get_many_chars(iv, wtls_machine->server_write_IV,0,ivLen); input = octstr_get_cstr(encryptedData); RC5_32_cbc_encrypt(input, output, dataLen, key, iv, RC5_DECRYPT); decryptedData = octstr_create_from_data(output, dataLen); gw_free(output); output = NULL; octstr_destroy(duplicatedIv); return encryptedData; } Octstr* wtls_decrypt_rsa(Octstr* encryptedData) { int numBytesWritten=0,numBytesToRead=0; Octstr *decryptedData=0; unsigned char* tempDecryptionBuffer=0; char* tempEncryptionPointer=0; /* Allocate some memory for our decryption buffer */ tempDecryptionBuffer = gw_malloc(RSA_size(private_key)); /* Calculate the number of bytes to read from encryptedData when decrypting */ numBytesToRead = octstr_len(encryptedData); /* Don't write to this pointer. Ever ever ever. */ tempEncryptionPointer = octstr_get_cstr(encryptedData); /* Decrypt the data in encryptedData */ numBytesWritten = RSA_private_decrypt(numBytesToRead, tempEncryptionPointer, tempDecryptionBuffer, private_key, RSA_PKCS1_PADDING); if(numBytesWritten == -1) { tempEncryptionPointer += 2; numBytesToRead -= 2; numBytesWritten = RSA_private_decrypt(numBytesToRead, tempEncryptionPointer, tempDecryptionBuffer, private_key, RSA_PKCS1_PADDING); } /* Move the tempDecryptionBuffer to an Octstr */ decryptedData = octstr_create_from_data(tempDecryptionBuffer,numBytesWritten); /* Deallocate the tempDecryptionBuffer */ gw_free(tempDecryptionBuffer); tempDecryptionBuffer = NULL; debug("wtls",0, "Decrypted secret"); octstr_dump( decryptedData, 0); /* Return the decrypted data */ return decryptedData; } void wtls_decrypt_pdu_list(WTLSMachine *wtls_machine, List *pdu_list) { int i, listlen; Octstr* decryptedData = NULL; wtls_Payload *payload; listlen = gwlist_len(pdu_list); for( i=0; icipher) { debug("wtls", 0, "Decrypting PDU %d", i); decryptedData = wtls_decrypt(payload->data, wtls_machine); /* replace the data */ octstr_destroy(payload->data); payload->data = decryptedData; } else { debug("wtls", 0, "PDU %d is not encrypted.", i); } } } RSAPublicKey* wtls_get_rsapublickey(void) { RSA* rsaStructure=0; EVP_PKEY* publicKey=0; BIGNUM *modulus=0,*exponent=0; unsigned char* tempModulusStorage=0,*tempExponentStorage=0; int numbytes=0; RSAPublicKey* returnStructure=0; Octstr *octstrModulus=0, *octstrExponent=0; /* First, we need to extract the RSA structure from the X509 Cert */ /* Get the EVP_PKEY structure from the X509 cert */ publicKey = X509_PUBKEY_get(x509_cert->cert_info->key); /* Take said EVP_PKEY structure and get the RSA component */ if (EVP_PKEY_type(publicKey->type) != EVP_PKEY_RSA) { return NULL; } else { rsaStructure = publicKey->pkey.rsa; } /* Then we need to grab the exponent component from the cert */ exponent = rsaStructure->e; /* We need to allocate sufficient memory to hold the exponent */ numbytes = BN_num_bytes(exponent); tempExponentStorage = gw_malloc(numbytes); /* Then we get the exponent */ numbytes = BN_bn2bin(exponent, tempExponentStorage); /* And finally we convert the exponent to an Octstr */ octstrExponent = octstr_create_from_data(tempExponentStorage,numbytes); /* Then we need to grab the modulus component from the cert */ modulus = rsaStructure->n; /* We need to allocate sufficient memory to hold the modulus */ numbytes = BN_num_bytes(modulus); tempModulusStorage = gw_malloc(numbytes); /* Then we get the modulus */ numbytes = BN_bn2bin(modulus, tempModulusStorage); /* And finally we convert the modulus to an Octstr */ octstrModulus = octstr_create_from_data(tempModulusStorage,numbytes); /* Put the components into our return structure */ returnStructure = gw_malloc(sizeof(RSAPublicKey)); returnStructure->rsa_exponent = octstrExponent; returnStructure->rsa_modulus = octstrModulus; /* And deallocate the memory allocated for holding the modulus */ gw_free(tempModulusStorage); gw_free(tempExponentStorage); tempModulusStorage = NULL; tempExponentStorage = NULL; return returnStructure; } Octstr* wtls_get_certificate(void) { unsigned char** pp; unsigned char* ppStart; int amountWritten = 1260; Octstr* returnOctstr; debug("wtls_get_certificate",0,"x509_cert : %x", x509_cert); /* Convert the x509 certificate to DER-encoding */ amountWritten =i2d_X509(x509_cert, NULL); debug("wtls_get_certificate",0,"amountWritten : %d", amountWritten); /* Allocate some memory for *pp */ pp = (unsigned char**) gw_malloc(sizeof(unsigned char**)); /* Allocate the memory and call the same function again?!!? What an original idea :-/ */ ppStart = (unsigned char *) gw_malloc (sizeof(unsigned char)*amountWritten); debug("wtls_get_certificate",0,"x509_cert_DER_pre : %x", *pp); *pp = ppStart; amountWritten =i2d_X509(x509_cert, pp); /* And we do this, because otherwise *pp is pointing to the end of the buffer. Yay */ *pp = ppStart; debug("wtls_get_certificate",0,"x509_cert_DER_post : %x", *pp); /* Convert the DER-encoded char string to an octstr */ returnOctstr = octstr_create_from_data(*pp,amountWritten); /* Destroy the memory allocated temporarily above */ gw_free(*pp); *pp = NULL; /* Destroy the memory allocated for pp as well */ gw_free(pp); pp = NULL; /* Return the octstr */ return returnOctstr; } /* Chooses a CipherSuite from the list provided by the client. Returns NULL if none is acceptable. */ CipherSuite* wtls_choose_ciphersuite(List* ciphersuites) { CipherSuite* returnSuite = NULL; CipherSuite* currentCS = NULL; int i = 0; int listLen; listLen = gwlist_len(ciphersuites); //returnSuite = gw_malloc(sizeof(CipherSuite)); /* the first CS in the list */ do { /* the next CS in the list */ currentCS = gwlist_get(ciphersuites, i); /* Check if we support this BulkCipher */ if(currentCS->bulk_cipher_algo >= RC5_CBC_40 && currentCS->bulk_cipher_algo <= IDEA_CBC) { /* Check if we support this MAC algsorithm */ if(currentCS->mac_algo >= SHA_0 && currentCS->mac_algo <= MD5_NOLIMIT) { /* We can use this CipherSuite then */ returnSuite = currentCS; } } i++; } while(returnSuite == NULL && i < listLen); return returnSuite; } int isSupportedKeyEx(int keyExId) { int maxSupported; int i; int retCode = 0; maxSupported = sizeof(supportedKeyExSuite) / sizeof(KeyExchangeSuite); for(i = 0; ikey_exchange_suite)) { returnKey = i+1; } i++; } while(returnKey == 0 && i < listLen); return returnKey; } int wtls_choose_snmode(int snmode) { return 2; } int wtls_choose_krefresh(int krefresh) { return 2; } Random* wtls_get_random(void) { Random* randomData; randomData = gw_malloc(sizeof(Random)); randomData->gmt_unix_time = 0x0000; /* Yeah, I know, it's not very random */ randomData->random_bytes = octstr_create("000000000000"); return randomData; } int clienthellos_are_identical (List* pdu_list, List* last_received_packet) { return 0; } int certifcateverifys_are_identical (List* pdu_list, List* last_received_packet) { return 0; } int certificates_are_identical (List* pdu_list, List* last_received_packet) { return 0; } int clientkeyexchanges_are_identical (List* pdu_list, List* last_received_packet) { return 0; } int changecipherspecs_are_identical (List* pdu_list, List* last_received_packet) { return 0; } int finisheds_are_indentical (List* pdu_list, List* last_received_packet) { return 0; } int packet_contains_changecipherspec (List* pdu_list) { return 0; } int packet_contains_finished (List* pdu_list) { return 0; } int packet_contains_optional_stuff (List* pdu_list) { return 0; } int packet_contains_userdata (List* pdu_list) { /* FIXME: need to check if it is really Userdata !! */ return 1; } int packet_contains_clienthello (List* pdu_list) { return 0; } int is_critical_alert (List* pdu_list) { return 0; } int is_warning_alert (List* pdu_list) { return 0; } /* go through the list of wtls_Payloads and add the data of any handshake message to wtls_machine->handshake_data */ void add_all_handshake_data(WTLSMachine *wtls_machine, List *pdu_list) { long i, listlen; wtls_Payload *payload; gw_assert(pdu_list != NULL); listlen = gwlist_len(pdu_list); debug("wtls", 0,"adding handshake data from %d PDU(s)", listlen); for(i=0; itype == Handshake_PDU) { octstr_insert(wtls_machine->handshake_data, payload->data, octstr_len(wtls_machine->handshake_data)); debug("wtls", 0, "Data from PDU %d:", i); octstr_dump(payload->data, 2); } } } void calculate_server_key_block(WTLSMachine *wtls_machine) { Octstr* concatenatedRandoms=0; Octstr* labelMaster=0; Octstr* key_block; Octstr* final_server_write_enc_key = NULL; Octstr* final_server_write_IV = NULL; Octstr* emptySecret = NULL; /* Concatenate our random data */ concatenatedRandoms = octstr_create(""); pack_int16(concatenatedRandoms, 0, wtls_machine->server_seq_num); octstr_append(concatenatedRandoms, wtls_machine->server_random); octstr_append(concatenatedRandoms, wtls_machine->client_random); /* Calculate the key_block */ labelMaster = octstr_create("server expansion"); key_block = wtls_calculate_prf(wtls_machine->master_secret, labelMaster, concatenatedRandoms, hash_table[wtls_machine->mac_algorithm].key_size + bulk_table[wtls_machine->bulk_cipher_algorithm].key_material + bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size, wtls_machine ); octstr_destroy(labelMaster); labelMaster = NULL; octstr_destroy(concatenatedRandoms); concatenatedRandoms = NULL; /* Break the key_block in its 3 parts */ wtls_machine->server_write_MAC_secret = octstr_copy(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size); octstr_delete(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size); wtls_machine->server_write_enc_key = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material); octstr_delete(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material); wtls_machine->server_write_IV = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size); /* Additional calculations for exportable encryption algos */ if(bulk_table[wtls_machine->bulk_cipher_algorithm].is_exportable == EXPORTABLE) { concatenatedRandoms = octstr_cat(wtls_machine->client_random, wtls_machine->server_random); labelMaster = octstr_create("server write key"); final_server_write_enc_key = wtls_calculate_prf(wtls_machine->server_write_enc_key, labelMaster, concatenatedRandoms, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material, wtls_machine); octstr_destroy(labelMaster); labelMaster = NULL; octstr_destroy(concatenatedRandoms); concatenatedRandoms = NULL; octstr_destroy(wtls_machine->server_write_enc_key); wtls_machine->server_write_enc_key = final_server_write_enc_key; final_server_write_enc_key = NULL; concatenatedRandoms = octstr_create(""); octstr_append_char(concatenatedRandoms, wtls_machine->server_seq_num); octstr_append(concatenatedRandoms, wtls_machine->client_random); octstr_append(concatenatedRandoms, wtls_machine->server_random); emptySecret = octstr_create(""); final_server_write_IV = wtls_calculate_prf(emptySecret, labelMaster, concatenatedRandoms, bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size, wtls_machine); octstr_destroy(labelMaster); labelMaster = NULL; octstr_destroy(concatenatedRandoms); concatenatedRandoms = NULL; } } void calculate_client_key_block(WTLSMachine *wtls_machine) { Octstr* concatenatedRandoms=0; Octstr* key_block; Octstr* final_client_write_enc_key = NULL; Octstr* final_client_write_IV = NULL; Octstr* emptySecret = NULL; Octstr* labelMaster=0; /* Concatenate our random data */ concatenatedRandoms = octstr_create(""); pack_int16(concatenatedRandoms, 0,wtls_machine->client_seq_num); octstr_append(concatenatedRandoms, wtls_machine->server_random); octstr_append(concatenatedRandoms, wtls_machine->client_random); /* Calculate the key_block */ labelMaster = octstr_create("client expansion"); key_block = wtls_calculate_prf(wtls_machine->master_secret, labelMaster, concatenatedRandoms, hash_table[wtls_machine->mac_algorithm].key_size + bulk_table[wtls_machine->bulk_cipher_algorithm].key_material + bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size, wtls_machine ); octstr_destroy(labelMaster); labelMaster = NULL; octstr_destroy(concatenatedRandoms); concatenatedRandoms = NULL; /* Break the key_block in its 3 parts */ wtls_machine->client_write_MAC_secret = octstr_copy(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size); octstr_delete(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size); wtls_machine->client_write_enc_key = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material); octstr_delete(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material); wtls_machine->client_write_IV = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size); /* Additional calculations for exportable encryption algos */ if(bulk_table[wtls_machine->bulk_cipher_algorithm].is_exportable == EXPORTABLE) { concatenatedRandoms = octstr_cat(wtls_machine->client_random, wtls_machine->server_random); labelMaster = octstr_create("client write key"); final_client_write_enc_key = wtls_calculate_prf(wtls_machine->client_write_enc_key, labelMaster, concatenatedRandoms, bulk_table[wtls_machine->bulk_cipher_algorithm].key_material, wtls_machine); octstr_destroy(labelMaster); labelMaster = NULL; octstr_destroy(wtls_machine->client_write_enc_key); wtls_machine->client_write_enc_key = final_client_write_enc_key; final_client_write_enc_key = NULL; octstr_destroy(labelMaster); labelMaster = NULL; octstr_destroy(concatenatedRandoms); concatenatedRandoms = NULL; emptySecret = octstr_create(""); final_client_write_IV = wtls_calculate_prf(emptySecret, labelMaster, concatenatedRandoms, bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size, wtls_machine); octstr_destroy(labelMaster); labelMaster = NULL; octstr_destroy(concatenatedRandoms); concatenatedRandoms = NULL; } } #endif