/* * Re-escape SMASI ASCII representation of binary data with the * original binary data octet string. * XXX this may be done by the internal parser routines too. */ static void decode_binary_data(Octstr *data) { long pos = 0; while (pos < octstr_len(data)) { int check = octstr_get_char(data, pos); if (check == ':') { Octstr *byte; int msb = octstr_get_char(data, pos + 1); int lsb = octstr_get_char(data, pos + 2); if (msb != -1 && lsb != -1) { byte = octstr_create(""); octstr_append_char(byte, msb); octstr_append_char(byte, lsb); if (octstr_hex_to_binary(byte) != -1) { /* Do inplace unescaping. */ octstr_delete(data, pos, 3); octstr_insert(data, byte, pos); } else { error(0, "Malformed binary encoded data."); } octstr_destroy(byte); } } pos++; } }
/* * Escapes outgoing message body data by replacing occurrences of "special" * chars inside the octet string. */ static void escape_data(Octstr *data) { long pos = 0; /* This one uses a different approach than the encode and decode * functions. Because it is assumed, that only a fraction of the * contained chars have to be escaped. */ while (pos < octstr_len(data)) { Octstr * escaped = NULL; int check = octstr_get_char(data, pos); if (check == ':') escaped = colon; else if (check == '=') escaped = assign; else if (check == ',') escaped = comma; else if (check == '\n') escaped = cr; else if (check == '\r') escaped = lf; if (escaped != NULL) { /* If the current char has to be escaped, delete the char from * the source string, replace it with the escape sequence, and * advance position until after the inserted sequence. */ octstr_delete(data, pos, 1); octstr_insert(data, escaped, pos); pos += octstr_len(escaped); } else { /* If not escaped, simply skip the current char. */ pos++; } } }
static void flag_date_length(Octstr **token) { Octstr *lenos; lenos = octstr_format("%c", octstr_len(*token) - 1); octstr_insert(*token, lenos, 1); octstr_destroy(lenos); }
/* * Add global tokens to the start and to the end of an inline string. */ void parse_inline_string(Octstr *temp, simple_binary_t **binary) { Octstr *startos; octstr_insert(temp, startos = octstr_format("%c", WBXML_STR_I), 0); octstr_destroy(startos); octstr_format_append(temp, "%c", WBXML_STR_END); parse_octet_string(temp, binary); }
static Octstr *cgw_decode_msg(Octstr* str) { int i; /* make \n -> linefeed */ while ((i = octstr_search(str, octstr_imm("\\n"), 0)) != -1) { octstr_delete(str, i, 2); /* delete "\n" str */ octstr_insert(str, octstr_imm("\n"), i); } /* make \r -> carriage return */ while ((i = octstr_search(str, octstr_imm("\\r"), 0)) != -1) { octstr_delete(str, i, 2); /* delete EOL char */ octstr_insert(str, octstr_imm("\r"), i); } /* remove double backslashes */ while ((i = octstr_search(str, octstr_imm("\\\\"), 0)) != -1) { octstr_delete(str, i, 1); } return str; }
static Octstr *cgw_encode_msg(Octstr* str) { int i; char esc = 27; char e = 'e'; /* Euro char (0x80) -> ESC + e. We do this conversion as long as the message length is under 160 chars (the checking could probably be done better) */ while ((i = octstr_search_char(str, 0x80, 0)) != -1) { octstr_delete(str, i, 1); /* delete Euro char */ if (octstr_len(str) < 160) { octstr_insert_data(str, i, &esc, 1); /* replace with ESC + e */ octstr_insert_data(str, i+1, &e, 1); } else { octstr_insert_data(str, i, &e, 1); /* no room for ESC + e, just replace with an e */ } } /* Escape backslash characters */ while ((i = octstr_search_char(str, '\\', 0)) != -1) { octstr_insert(str, octstr_imm("\\"), i); } /* Remove Line Feed characters */ while ((i = octstr_search_char(str, CGW_EOL, 0)) != -1) { octstr_delete(str, i, 1); /* delete EOL char */ octstr_insert(str, octstr_imm("\\n"), i); } /* Remove Carriage return characters */ while ((i = octstr_search_char(str, 13, 0)) != -1) { octstr_delete(str, i, 1); /* delete EOL char */ octstr_insert(str, octstr_imm("\\r"), i); } return str; }
Octstr *radius_pdu_pack(RADIUS_PDU *pdu) { Octstr *os,*oos; Octstr *temp; os = octstr_create(""); gw_assert(pdu != NULL); /* switch (pdu->type) { #define INTEGER(name, octets) p = *(&p); #define NULTERMINATED(name, max_octets) p = *(&p); #define OCTETS(name, field_giving_octets) \ p->field_giving_octets = octstr_len(p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error while packing."); } */ switch (pdu->type) { #define INTEGER(name, octets) \ append_encoded_integer(os, p->name, octets); #define OCTETS(name, field_giving_octets) \ octstr_append(os, p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields; oos = radius_attr_pack(pdu); \ octstr_append(os, oos);octstr_destroy(oos); } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error while packing."); } /* now set PDU length */ temp = octstr_create(""); append_encoded_integer(temp, octstr_len(os), 2); octstr_delete(os, 2, 2); octstr_insert(os, temp, 2); octstr_destroy(temp); return os; }
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; }
Octstr *smasi_pdu_pack(SMASI_PDU *pdu) { Octstr *os; Octstr *temp; os = octstr_create(""); /* * Fix lengths of octet string fields. */ switch (pdu->type) { #define NONTERMINATED(name) p = *(&p); #define COMATERMINATED(name) p = *(&p); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smasi_pdu.def" default: error(0, "Unknown SMASI_PDU type, internal error while packing."); } switch (pdu->type) { #define NONTERMINATED(name) p = *(&p); #define COMATERMINATED(name) \ if (p->name != NULL) { octstr_append_cstr(os, #name); \ octstr_append_char(os, '='); \ octstr_append(os, p->name); \ octstr_append_char(os, ','); } #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smasi_pdu.def" default: error(0, "Unknown SMASI_PDU type, internal error while packing."); } octstr_append_char(os, '\n'); temp = pdu->needs_hyphen ? octstr_create("!") : octstr_create(""); octstr_append_cstr(temp, pdu->type_name); octstr_append_char(temp, ':'); octstr_insert(os, temp, 0); octstr_destroy(temp); return os; }
int radius_authenticate_pdu(RADIUS_PDU *pdu, Octstr **data, Octstr *secret) { int rc = 0; Octstr *stream; Octstr *attributes; Octstr *digest; stream = attributes = digest = NULL; /* first extract attributes from raw data, where * the first 20 octets are code, idendifier, length * and authenticator value as described in RFC2866, sec. 3 */ if (octstr_len(*data) > 20) attributes = octstr_copy(*data, 20, octstr_len(*data)-20); switch (pdu->type) { case 0x04: /* Accounting-Request, see RFC2866, page 6 */ stream = octstr_copy(*data, 0, 4); octstr_append_data(stream, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16); octstr_append(stream, attributes); octstr_append(stream, secret); digest = md5(stream); rc = octstr_compare(pdu->u.Accounting_Request.authenticator, digest) == 0 ? 1 : 0; break; case 0x05: /* Accounting-Response, create Response authenticator */ stream = octstr_duplicate(*data); octstr_append(stream, secret); digest = md5(stream); octstr_delete(*data, 4, 16); octstr_insert(*data, digest, 4); break; default: break; } octstr_destroy(attributes); octstr_destroy(stream); octstr_destroy(digest); return rc; }
static void add_crs(Octstr *os) { long i; Octstr *nos; if (os == NULL) return; nos = octstr_format("%c", '\r'); i = 0; while (i < octstr_len(os)) { if (octstr_get_char(os, i) == '\n') { octstr_insert(os, nos, i); ++i; } ++i; } octstr_destroy(nos); }
static void add_pdu(WTLSMachine * wtls_machine, wtls_PDU * pduToAdd) { int currentLength; wtls_Payload *payloadToAdd; Octstr *packedPDU; /* Update sequence number before encryption */ wtls_machine->server_seq_num++; /* Pack and encrypt the pdu */ if (!(payloadToAdd = wtls_pdu_pack(pduToAdd, wtls_machine))) { wtls_machine->server_seq_num--; return; } if (!payloadToAdd->data) { wtls_machine->server_seq_num--; wtls_payload_destroy(payloadToAdd); return; } /* Check to see if we've already allocated some memory for the list */ if (!wtls_machine->packet_to_send) wtls_machine->packet_to_send = octstr_create(""); /* If the pdu is a Handshake pdu, append the Octstr to our wtls_machine's exchanged_handshakes Octstr */ packedPDU = wtls_payload_pack(payloadToAdd, wtls_machine->server_seq_num); if (pduToAdd->type == ChangeCipher_PDU) wtls_machine->server_seq_num = -1; /* Add it to our list */ currentLength = octstr_len(wtls_machine->packet_to_send); octstr_insert(wtls_machine->packet_to_send, packedPDU, currentLength); wtls_payload_destroy(payloadToAdd); octstr_destroy(packedPDU); }
Octstr *smpp_pdu_pack(SMPP_PDU *pdu) { Octstr *os; Octstr *temp; os = octstr_create(""); gw_assert(pdu != NULL); /* * Fix lengths of octet string fields. */ switch (pdu->type) { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) #define TLV_NULTERMINATED(name, max_len) #define TLV_OCTETS(name, min_len, max_len) #define OPTIONAL_END #define INTEGER(name, octets) p = *(&p); #define NULTERMINATED(name, max_octets) p = *(&p); #define OCTETS(name, field_giving_octets) \ p->field_giving_octets = octstr_len(p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error while packing."); } switch (pdu->type) { #define TL(name, octets) \ append_encoded_integer(os, SMPP_##name, 2); \ append_encoded_integer(os, octets, 2); #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) \ if (p->name != -1) { \ TL(name, octets); \ INTEGER(name, octets) \ } #define TLV_NULTERMINATED(name, max_len) \ if (p->name != NULL) { \ TL(name, (octstr_len(p->name) > max_len ? max_len : octstr_len(p->name))); \ NULTERMINATED(name, max_len) \ } #define TLV_OCTETS(name, min_len, max_len) \ if (p->name != NULL) { \ unsigned long len = octstr_len(p->name); \ if (len > max_len || len < min_len) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \ #name, len, min_len, max_len);\ } else { \ TL(name, len); \ octstr_append(os, p->name); \ } \ } #define OPTIONAL_END #define INTEGER(name, octets) \ append_encoded_integer(os, p->name, octets); #define NULTERMINATED(name, max_octets) \ if (p->name != NULL) { \ if (octstr_len(p->name) >= max_octets) { \ warning(0, "SMPP: PDU element <%s> too long " \ "(length is %ld, should be %d)", \ #name, octstr_len(p->name), max_octets-1); \ temp = octstr_copy(p->name, 0, max_octets-1); \ } else \ temp = octstr_duplicate(p->name); \ octstr_append(os, temp); \ octstr_destroy(temp); \ } \ octstr_append_char(os, '\0'); #define OCTETS(name, field_giving_octets) \ if (p->name) octstr_append(os, p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error while packing."); } temp = octstr_create(""); append_encoded_integer(temp, octstr_len(os) + 4, 4); octstr_insert(os, temp, 0); octstr_destroy(temp); return os; }
static void prepend_crlf(Octstr **os) { octstr_insert(*os, octstr_imm("\r\n"), 0); }
int main(int argc, char **argv) { output_t outputti = NORMAL_OUT; FILE *fp = NULL; Octstr *output = NULL; Octstr *filename = NULL; Octstr *wml_text = NULL; Octstr *charset = NULL; Octstr *wml_binary = NULL; int i, ret = 0, opt, file = 0, zero = 0, numstatus = 0, wml_strict = 1; long num = 0; /* You can give an wml text file as an argument './wml_tester main.wml' */ gwlib_init(); while ((opt = getopt(argc, argv, "hsbzrn:f:c:")) != EOF) { switch (opt) { case 'h': help(); exit(0); case 's': if (outputti == NORMAL_OUT) outputti = SOURCE_OUT; else { help(); exit(0); } break; case 'b': if (outputti == NORMAL_OUT) outputti = BINARY_OUT; else { help(); exit(0); } break; case 'z': zero = 1; break; case 'r': wml_strict = 0; break; case 'n': numstatus = octstr_parse_long(&num, octstr_imm(optarg), 0, 0); if (numstatus == -1) { /* Error in the octstr_parse_long */ error(num, "Error in the handling of argument to option n"); help(); panic(0, "Stopping."); } break; case 'f': file = 1; filename = octstr_create(optarg); fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Couldn't open output file."); break; case 'c': charset = octstr_create(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (optind >= argc) { error(0, "Missing arguments."); help(); panic(0, "Stopping."); } if (outputti == BINARY_OUT) log_set_output_level(GW_PANIC); wml_init(wml_strict); while (optind < argc) { wml_text = octstr_read_file(argv[optind]); if (wml_text == NULL) panic(0, "Couldn't read WML source file."); if (zero) set_zero(wml_text); for (i = 0; i <= num; i++) { ret = wml_compile(wml_text, charset, &wml_binary, NULL); if (i < num) octstr_destroy(wml_binary); } optind++; output = octstr_format("wml_compile returned: %d\n\n", ret); if (ret == 0) { if (fp == NULL) fp = stdout; if (outputti != BINARY_OUT) { if (outputti == SOURCE_OUT) { octstr_insert(output, wml_text, octstr_len(output)); octstr_append_char(output, '\n'); } octstr_append(output, octstr_imm( "Here's the binary output: \n\n")); octstr_print(fp, output); } if (file && outputti != BINARY_OUT) { fclose(fp); log_open(octstr_get_cstr(filename), 0, GW_NON_EXCL); octstr_dump(wml_binary, 0); log_close_all(); fp = fopen(octstr_get_cstr(filename), "a"); } else if (outputti != BINARY_OUT) octstr_dump(wml_binary, 0); else octstr_print(fp, wml_binary); if (outputti != BINARY_OUT) { octstr_destroy(output); output = octstr_format("\n And as a text: \n\n"); octstr_print(fp, output); octstr_pretty_print(fp, wml_binary); octstr_destroy(output); output = octstr_format("\n\n"); octstr_print(fp, output); } } octstr_destroy(wml_text); octstr_destroy(output); octstr_destroy(wml_binary); } if (file) { fclose(fp); octstr_destroy(filename); } if (charset != NULL) octstr_destroy(charset); wml_shutdown(); gwlib_shutdown(); return ret; }
/* * Populates the corresponding smsbox_by_foobar dictionary hash tables */ static void init_smsbox_routes(Cfg *cfg) { CfgGroup *grp; List *list, *items; Octstr *boxc_id, *smsc_ids, *shortcuts; int i, j; boxc_id = smsc_ids = shortcuts = NULL; list = cfg_get_multi_group(cfg, octstr_imm("smsbox-route")); /* loop multi-group "smsbox-route" */ while (list && (grp = gwlist_extract_first(list)) != NULL) { if ((boxc_id = cfg_get(grp, octstr_imm("smsbox-id"))) == NULL) { grp_dump(grp); panic(0,"'smsbox-route' group without valid 'smsbox-id' directive!"); } /* * If smsc-id is given, then any message comming from the specified * smsc-id in the list will be routed to this smsbox instance. * If shortcode is given, then any message with receiver number * matching those will be routed to this smsbox instance. * If both are given, then only receiver within shortcode originating * from smsc-id list will be routed to this smsbox instance. So if both * are present then this is a logical AND operation. */ smsc_ids = cfg_get(grp, octstr_imm("smsc-id")); shortcuts = cfg_get(grp, octstr_imm("shortcode")); /* consider now the 3 possibilities: */ if (smsc_ids && !shortcuts) { /* smsc-id only, so all MO traffic */ items = octstr_split(smsc_ids, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); debug("bb.boxc",0,"Adding smsbox routing to id <%s> for smsc id <%s>", octstr_get_cstr(boxc_id), octstr_get_cstr(item)); if (!dict_put_once(smsbox_by_smsc, item, octstr_duplicate(boxc_id))) panic(0, "Routing for smsc-id <%s> already exists!", octstr_get_cstr(item)); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(smsc_ids); } else if (!smsc_ids && shortcuts) { /* shortcode only, so these MOs from all smscs */ items = octstr_split(shortcuts, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); debug("bb.boxc",0,"Adding smsbox routing to id <%s> for receiver no <%s>", octstr_get_cstr(boxc_id), octstr_get_cstr(item)); if (!dict_put_once(smsbox_by_receiver, item, octstr_duplicate(boxc_id))) panic(0, "Routing for receiver no <%s> already exists!", octstr_get_cstr(item)); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(shortcuts); } else if (smsc_ids && shortcuts) { /* both, so only specified MOs from specified smscs */ items = octstr_split(shortcuts, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { List *subitems; Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); subitems = octstr_split(smsc_ids, octstr_imm(";")); for (j = 0; j < gwlist_len(subitems); j++) { Octstr *subitem = gwlist_get(subitems, j); octstr_strip_blanks(subitem); debug("bb.boxc",0,"Adding smsbox routing to id <%s> " "for receiver no <%s> and smsc id <%s>", octstr_get_cstr(boxc_id), octstr_get_cstr(item), octstr_get_cstr(subitem)); /* construct the dict key '<shortcode>:<smsc-id>' */ octstr_insert(subitem, item, 0); octstr_insert_char(subitem, octstr_len(item), ':'); if (!dict_put_once(smsbox_by_smsc_receiver, subitem, octstr_duplicate(boxc_id))) panic(0, "Routing for receiver:smsc <%s> already exists!", octstr_get_cstr(subitem)); } gwlist_destroy(subitems, octstr_destroy_item); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(shortcuts); } octstr_destroy(boxc_id); } gwlist_destroy(list, NULL); }
Octstr *smpp_pdu_pack(Octstr *smsc_id, SMPP_PDU *pdu) { Octstr *os; Octstr *temp; os = octstr_create(""); gw_assert(pdu != NULL); /* * Fix lengths of octet string fields. */ switch (pdu->type) { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) #define TLV_NULTERMINATED(name, max_len) #define TLV_OCTETS(name, min_len, max_len) #define OPTIONAL_END #define INTEGER(name, octets) p = *(&p); #define NULTERMINATED(name, max_octets) p = *(&p); #define OCTETS(name, field_giving_octets) \ p->field_giving_octets = octstr_len(p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error while packing."); } switch (pdu->type) { #define TL(name, octets) \ append_encoded_integer(os, SMPP_##name, 2); \ append_encoded_integer(os, octets, 2); #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) \ if (p->name >= 0) { \ TL(name, octets); \ INTEGER(name, octets) \ } #define TLV_NULTERMINATED(name, max_len) \ if (p->name != NULL) { \ TL(name, (octstr_len(p->name) > max_len ? max_len : octstr_len(p->name) + 1)); \ NULTERMINATED(name, max_len) \ } #define TLV_OCTETS(name, min_len, max_len) \ if (p->name != NULL) { \ unsigned long len = octstr_len(p->name); \ if (len > max_len || len < min_len) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \ #name, len, min_len, max_len);\ } else { \ TL(name, len); \ octstr_append(os, p->name); \ } \ } #define OPTIONAL_END \ if (p->tlv != NULL) { \ Octstr *key; \ List *keys; \ struct smpp_tlv *tlv; \ keys = dict_keys(p->tlv); \ while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \ tlv = smpp_tlv_get_by_name(smsc_id, key); \ if (tlv == NULL) { \ error(0, "SMPP: Unknown TLV `%s', don't send.", octstr_get_cstr(key)); \ octstr_destroy(key); \ continue; \ } \ switch(tlv->type) { \ case SMPP_TLV_INTEGER: { \ long val = atol(octstr_get_cstr(dict_get(p->tlv, key))); \ append_encoded_integer(os, tlv->tag, 2); \ append_encoded_integer(os, tlv->length, 2); \ append_encoded_integer(os, val, tlv->length); \ break; \ } \ case SMPP_TLV_OCTETS: \ case SMPP_TLV_NULTERMINATED: { \ Octstr *val = dict_get(p->tlv, key); \ unsigned long len = octstr_len(val); \ if (len > tlv->length) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %ld) dropped.", \ octstr_get_cstr(key), len, tlv->length);\ octstr_destroy(key); \ continue; \ } \ append_encoded_integer(os, tlv->tag, 2); \ if (tlv->type == SMPP_TLV_NULTERMINATED) \ append_encoded_integer(os, len + 1, 2); \ else \ append_encoded_integer(os, len, 2); \ octstr_append(os, val); \ if (tlv->type == SMPP_TLV_NULTERMINATED) \ octstr_append_char(os, '\0'); \ break; \ } \ default: \ panic(0, "SMPP: Internal error, unknown configured TLV type %d.", tlv->type); \ break; \ } \ octstr_destroy(key); \ } \ gwlist_destroy(keys, octstr_destroy_item); \ } #define INTEGER(name, octets) \ append_encoded_integer(os, p->name, octets); #define NULTERMINATED(name, max_octets) \ if (p->name != NULL) { \ if (octstr_len(p->name) >= max_octets) { \ warning(0, "SMPP: PDU element <%s> too long " \ "(length is %ld, should be %d)", \ #name, octstr_len(p->name), max_octets-1); \ temp = octstr_copy(p->name, 0, max_octets-1); \ } else \ temp = octstr_duplicate(p->name); \ octstr_append(os, temp); \ octstr_destroy(temp); \ } \ octstr_append_char(os, '\0'); #define OCTETS(name, field_giving_octets) \ if (p->name) octstr_append(os, p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type 0x%08lx, internal error while packing.", pdu->type); break; } temp = octstr_create(""); append_encoded_integer(temp, octstr_len(os) + 4, 4); octstr_insert(os, temp, 0); octstr_destroy(temp); return os; }
void output_octet_string(Octstr *os, simple_binary_t **sibxml) { octstr_insert((*sibxml)->binary, os, octstr_len((*sibxml)->binary)); }
static void clientHello(WAPEvent * event, WTLSMachine * wtls_machine) { /* The Wap event we have to dispatch */ WAPEvent *res; wtls_Payload *tempPayload; wtls_PDU *clientHelloPDU; CipherSuite *ciphersuite; int randomCounter, algo; tempPayload = (wtls_Payload *) gwlist_search(event->u.T_Unitdata_Ind.pdu_list, (void *)client_hello, match_handshake_type); if (!tempPayload) { error(0, "Illegal PDU while waiting for a ClientHello"); fatalAlert(event, unexpected_message); return; } clientHelloPDU = wtls_pdu_unpack(tempPayload, wtls_machine); /* Store the client's random value - use pack for simplicity */ wtls_machine->client_random = octstr_create(""); randomCounter = pack_int32(wtls_machine->client_random, 0, clientHelloPDU->u.handshake.client_hello-> random->gmt_unix_time); octstr_insert(wtls_machine->client_random, clientHelloPDU->u.handshake.client_hello->random-> random_bytes, randomCounter); /* Select the ciphersuite from the supplied list */ ciphersuite = wtls_choose_ciphersuite(clientHelloPDU->u.handshake.client_hello-> ciphersuites); if (!ciphersuite) { error(0, "Couldn't agree on encryption cipher. Aborting"); wtls_pdu_destroy(clientHelloPDU); fatalAlert(event, handshake_failure); return; } /* Set the relevant values in the wtls_machine and PDU structure */ wtls_machine->bulk_cipher_algorithm = ciphersuite->bulk_cipher_algo; wtls_machine->mac_algorithm = ciphersuite->mac_algo; /* Generate a SEC_Create_Res event, and pass it back into the queue */ res = wap_event_create(SEC_Create_Res); res->u.SEC_Create_Res.addr_tuple = wap_addr_tuple_duplicate(event->u.T_Unitdata_Ind.addr_tuple); res->u.SEC_Create_Res.bulk_cipher_algo = ciphersuite->bulk_cipher_algo; res->u.SEC_Create_Res.mac_algo = ciphersuite->mac_algo; res->u.SEC_Create_Res.client_key_id = wtls_choose_clientkeyid (clientHelloPDU->u.handshake.client_hello->client_key_ids, &algo); if (!res->u.SEC_Create_Res.client_key_id) { error(0, "Couldn't agree on key exchange protocol. Aborting"); wtls_pdu_destroy(clientHelloPDU); wap_event_destroy(res); fatalAlert(event, unknown_key_id); return; } wtls_machine->key_algorithm = algo; /* Set the sequence number mode in both the machine and the outgoing packet */ res->u.SEC_Create_Res.snmode = wtls_choose_snmode(clientHelloPDU->u.handshake.client_hello-> snmode); wtls_machine->sequence_number_mode = res->u.SEC_Create_Res.snmode; /* Set the key refresh mode in both the machine and the outgoing packet */ res->u.SEC_Create_Res.krefresh = clientHelloPDU->u.handshake.client_hello->krefresh; wtls_machine->key_refresh = res->u.SEC_Create_Res.krefresh; /* Global refresh variable */ debug("wtls", 0, "clientHello ~> Accepted refresh = %d, refresh_rate = " "%d", wtls_machine->key_refresh, 1 << wtls_machine->key_refresh); /* Keep the data so we can send it back in EXCHANGE * temporary - needs to delete old one if exists ! * wtls_machine->handshake_data = octstr_create(""); */ if (wtls_machine->handshake_data) octstr_destroy(wtls_machine->handshake_data); wtls_machine->handshake_data = octstr_create(""); octstr_append(wtls_machine->handshake_data, tempPayload->data); debug("wtls", 0, "clientHello ~> Dispatching SEC_Create_Res event"); wtls_pdu_destroy(clientHelloPDU); wtls_dispatch_event(res); }
static void serverHello(WAPEvent * event, WTLSMachine * wtls_machine) { WAPEvent *req; wtls_PDU *serverHelloPDU; // wtls_PDU* certificatePDU; Random *tempRandom; /* List *certList; Certificate *cert; */ int randomCounter = 0; /* Our serverHello */ serverHelloPDU = wtls_pdu_create(Handshake_PDU); serverHelloPDU->rlen = 1; serverHelloPDU->snMode = wtls_machine->sequence_number_mode ? 1 : 0; serverHelloPDU->u.handshake.msg_type = server_hello; serverHelloPDU->u.handshake.server_hello = (ServerHello *) gw_malloc(sizeof(ServerHello)); /* Set our server version */ serverHelloPDU->u.handshake.server_hello->serverversion = 1; /* Get a suitably random number - store it in both the machine structure and outgoing PDU */ tempRandom = wtls_get_random(); wtls_machine->server_random = octstr_create(""); randomCounter = pack_int32(wtls_machine->server_random, 0, tempRandom->gmt_unix_time); octstr_insert(wtls_machine->server_random, tempRandom->random_bytes, octstr_len(wtls_machine->server_random)); serverHelloPDU->u.handshake.server_hello->random = tempRandom; /* At the moment, we don't support session caching, so tell them to forget about caching us */ serverHelloPDU->u.handshake.server_hello->session_id = octstr_format("%llu", wtls_machine->mid); /* We need to select an appropriate mechanism here from the ones listed */ serverHelloPDU->u.handshake.server_hello->client_key_id = event->u.SEC_Create_Res.client_key_id; /* Get our ciphersuite details */ serverHelloPDU->u.handshake.server_hello->ciphersuite = (CipherSuite *) gw_malloc(sizeof(CipherSuite)); serverHelloPDU->u.handshake.server_hello->ciphersuite->bulk_cipher_algo = event->u.SEC_Create_Res.bulk_cipher_algo; serverHelloPDU->u.handshake.server_hello->ciphersuite->mac_algo = event->u.SEC_Create_Res.mac_algo; serverHelloPDU->u.handshake.server_hello->comp_method = null_comp; /* We need to confirm the client's choice, or if they haven't * specified one, select one ourselves */ serverHelloPDU->u.handshake.server_hello->snmode = event->u.SEC_Create_Res.snmode; /* We need to either confirm the client's choice of key refresh rate, or choose a lower rate */ serverHelloPDU->u.handshake.server_hello->krefresh = event->u.SEC_Create_Res.krefresh; /* Add the PDUsto the server's outgoing list */ add_pdu(wtls_machine, serverHelloPDU); wtls_pdu_destroy(serverHelloPDU); /* Generate and dispatch a SEC_Exchange_Req or maybe a SEC_Commit_Req */ req = wap_event_create(SEC_Exchange_Req); req->u.SEC_Exchange_Req.addr_tuple = wap_addr_tuple_duplicate(event->u.T_Unitdata_Ind.addr_tuple); wtls_dispatch_event(req); debug("wtls", 0, "serverHello ~> Dispatching SEC_Exchange_Req event"); }
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); }