wtls_pdu.c

来自「mms client」· C语言 代码 · 共 998 行 · 第 1/3 页

C
998
字号
/*  * wtls_pdu.c: pack and unpack WTLS packets * * Generates packing and unpacking code from wtls_pdu.def. * */#include "gwlib/gwlib.h"#if (HAVE_WTLS_OPENSSL)#include "gwlib/octstr.h"#include "wtls_pdu.h"#include "wtls_pdusupport.h"#include "wtls_statesupport.h"KeyExchangeSuite client_key_exchange_algo = rsa_anon;PublicKeyAlgorithm public_key_algo;SignatureAlgorithm signature_algo;int seqnum;wtls_Payload* wtls_payload_unpack_from_offset (Octstr *data, int *offset);wtls_PDU *wtls_pdu_create(int type) {        wtls_PDU *pdu;                pdu = gw_malloc(sizeof(*pdu));        pdu->type = type;        pdu->reserved = 0;        pdu->cipher = 0;        pdu->seqnum = 0;        pdu->rlen = 0;                switch (pdu->type) {        case ChangeCipher_PDU:                pdu->u.cc.change = 1;				break;        case Alert_PDU:                pdu->u.alert.level = 0;                pdu->u.alert.desc = 0;                pdu->u.alert.chksum = 0;				break;        case Handshake_PDU:                pdu->u.handshake.msg_type = 0;                pdu->u.handshake.length = 0;				break;        case Application_PDU:                pdu->u.application.data = NULL;				break;        default:                warning(0, "Cannot create unknown WTLS PDU type %d", pdu->type);                break;        }        return pdu;}void wtls_payload_destroy(wtls_Payload *payload) {		octstr_destroy(payload->data);		gw_free(payload);}void wtls_pdu_destroy(wtls_PDU *pdu) {        if (pdu == NULL)                return;        switch (pdu->type) {        case ChangeCipher_PDU:				/* no memory was allocated for ChangeCipher_PDU */ 				break;        case Alert_PDU:				octstr_destroy(pdu->u.alert.chksum	);				break;        case Handshake_PDU:                switch (pdu->u.handshake.msg_type) {                case hello_request:						break;                case client_hello:						destroy_random(pdu->u.handshake.client_hello->random);						octstr_destroy(pdu->u.handshake.client_hello->session_id);						destroy_key_list(pdu->u.handshake.client_hello->client_key_ids);						destroy_key_list(pdu->u.handshake.client_hello->trusted_key_ids);						destroy_ciphersuite_list(pdu->u.handshake.client_hello->ciphersuites);						destroy_compression_method_list(pdu->u.handshake.client_hello->comp_methods);						/* destroy the client_hello struct */						gw_free(pdu->u.handshake.client_hello);						break;                case server_hello:						destroy_random(pdu->u.handshake.server_hello->random);						octstr_destroy(pdu->u.handshake.server_hello->session_id);						/* destroy the server_hello struct */						gw_free(pdu->u.handshake.server_hello);						break;                case certificate:                        switch (pdu->u.handshake.certificate->certificateformat) {                        case WTLSCert:								destroy_wtls_certificate(pdu->u.handshake.certificate->wtls_certificate);                                break;                        case X509Cert:								octstr_destroy(pdu->u.handshake.certificate->x509_certificate);                                break;                        case X968Cert:								octstr_destroy(pdu->u.handshake.certificate->x968_certificate);                                break;                        }						gw_free(pdu->u.handshake.certificate);						break;                case server_key_exchange:						destroy_param_spec(pdu->u.handshake.server_key_exchange->param_spec);                        switch (client_key_exchange_algo) {                        case rsa_anon:								destroy_rsa_pubkey(pdu->u.handshake.server_key_exchange->rsa_params);								break;                        case dh_anon:                                destroy_dh_pubkey(pdu->u.handshake.server_key_exchange->dh_params);								break;                        case ecdh_anon:                                destroy_ec_pubkey(pdu->u.handshake.server_key_exchange->ecdh_params);								break;						}						gw_free(pdu->u.handshake.server_key_exchange);						break;                case client_key_exchange:                        switch (client_key_exchange_algo) {                        case rsa:                        case rsa_anon:                                destroy_rsa_encrypted_secret(pdu->u.handshake.client_key_exchange->rsa_params);                                break;                        case dh_anon:                                destroy_dh_pubkey(pdu->u.handshake.client_key_exchange->dh_anon_params);                                break;                        case ecdh_anon:                        case ecdh_ecdsa:                                destroy_ec_pubkey(pdu->u.handshake.client_key_exchange->ecdh_params);								break;						}						gw_free(pdu->u.handshake.client_key_exchange);						break;                case server_hello_done:						/* nothing to do here */                    	break;                }				break;        case Application_PDU:				octstr_destroy(pdu->u.application.data);				break;        }        gw_free(pdu);}/* 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 (list_len(payloadlist) > 0) {                                /* Retrieve the next payload from the payloadlist */                retrievedPDU = (wtls_Payload*) list_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;}/* This function will unpack an Octstr and return a list of all PDUs contained   within that Octstr. If the contents of the packet are garbled in some fashion,   and one packet fails to be decoded correctly, we will continue regardless, and   a partial list will be returned. NULL is returned if no PDUs can be successfully   decoded from the supplied data */List* wtls_unpack_payloadlist (Octstr *data) {        List* payloadlist = NULL;        int offset = 0;        int dataLength = 0;        wtls_Payload* tempPayload;                /* Has somebody passed in an unpack of a null pointer ? */        gw_assert(data != NULL);                /* Initialise our list */        payloadlist = list_create();        dataLength = octstr_len(data);                /* While offset is less than the size of the data */        while( offset < dataLength) {                debug("wtls:wtls_unpack_payloadlist",0,"Offset is now : %d", offset);                /* Unpack from the supplied offset. This will bump up the value of offset */                tempPayload = wtls_payload_unpack_from_offset (data, &offset);                                /* If the packet returned is not NULL */                if (tempPayload != NULL) {                        /* Add the returned packet to the current list of packets */                        list_append(payloadlist, (void*) tempPayload);                }        }        debug("wtls:wtls_unpack_payloadlist",0,"Finished, found %d PDUs", list_len(payloadlist));                /* If the length of the list is greater than 0 */        if (list_len(payloadlist) > 0) {                /* Return the List */                return payloadlist;        }                /* Otherwise return NULL */        return NULL;}/* This function tries to determine the length of the PDU at the start of the   supplied Octstr using (somewhat) intelligent means. If the packet is screwed   up in some fashion, returns length -1. Returns an int. */int wtls_payload_guess_length(Octstr* data) {        int type = 0, lengthFlag = 0, lengthSize = 0, pdu_length = 0;        long lengthOffset = 1;                /* Is the fragment length indicator on? */        lengthFlag = octstr_get_bits(data, 0, 1);        if (lengthFlag) {                lengthSize = 2;        }                /* Is the sequence number indicator on? */        if (octstr_get_bits(data, 1, 1)) {                /* Yes, so hop over two extra bytes when reading the length */                lengthOffset += 2;        }        /* the message type */        type = octstr_get_bits(data, 4, 4);                /* If fragment length is turned on, jump to the necessary spot */        if (lengthFlag == 1) {                /* After this, lengthOffset + pdu_length == the total length of the PDU */                pdu_length = unpack_int16(data, &lengthOffset);                     }        /* Oh great, so it's not switched on. How considerate. We'll have to make           a reasonable guess as to what it might be. */        else {                switch (type) {                case ChangeCipher_PDU:                        /* They're really short */                        pdu_length = 1;                        break;                                        case Alert_PDU:                        /* They're a bit longer */                        pdu_length = 6;                        break;                default:                        /* Otherwise just give up and play dead */                        pdu_length = -1;                        break;                }        }        /* And that's the length of the contents, now just add the other doodads on */        if (pdu_length == -1) {                return -1;        }        else {                /* The pdu length, plus the sequence number, plus the length of the length value,                   plus the actual header byte */                return (pdu_length + lengthOffset);        }}/* This function will unpack an Octstr, starting at the specified offset, and   return the corresponding wtls_PDU* which was generated from that offset. Offset   is changed during the running of this function, and ends up as the octet at the start of the   next pdu */wtls_Payload* wtls_payload_unpack_from_offset (Octstr *data, int *offset) {        int guessedPayloadLength = 0;        int dataLength = 0;        Octstr* dataFromOffset = 0;        Octstr* dataFromOffsetToLength = 0;        wtls_Payload* returnPayload = 0;                /* This would be a sure sign of trouble */        gw_assert (offset != NULL);        gw_assert (data != NULL);        gw_assert (octstr_len(data) >= *offset);        dataLength = octstr_len(data);                /* First, we need to figure out how long a PDU starting from           the specified offset is going to be. We need to peek quickly into the           PDU to check this */        dataFromOffset = octstr_copy(data, *offset, dataLength);        guessedPayloadLength = wtls_payload_guess_length(dataFromOffset);        /* Ooops. Something's wrong. This requested PDU is screwed up. */        if (guessedPayloadLength == -1) {                *offset = dataLength;                return NULL;        }                /* Quit if we discover that the PDU length plus the requested offset is           larger than the length of the data supplied - this would mean that we           would overrun our data, and therefore something is corrupt in this PDU.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?