diff --git a/config.c b/config.c index 2d36301..8cf2cdc 100644 --- a/config.c +++ b/config.c @@ -93,6 +93,9 @@ STATUS read_rsa_keys(void) { fclose(file); res = rsa_keypair_from_sexp(pub, priv, 0, size, buffer); + if (!res) { + DEBUG(0, "Error reading the RSA keypair from the SEXP file"); + } conf->public_key = pub; conf->private_key = priv; diff --git a/secip.idl b/secip.idl index 689d2bd..5abfdbc 100644 --- a/secip.idl +++ b/secip.idl @@ -41,7 +41,7 @@ interface secip typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { [value(0)] uint16 session_id; uint8 rsa_key[128]; - uint8 padding[75]; + uint8 padding[74]; } secip_ppk_com; typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { @@ -51,28 +51,34 @@ interface secip typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { [value(1)] uint8 protocol_version; - uint8 manufacturer[8]; + uint8 manufacturer[20]; uint8 panel_type[12]; uint8 panel_version[8]; uint8 account_code[6]; uint8 crc_mode; uint16 session_id; secip_key_message_block key_block; - uint8 padding[137]; + uint8 padding[136]; } secip_ppk_rep; typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { secip_error error_code; uint16 session_id; - uint8 padding[232]; + uint8 padding[231]; } secip_arc_enc; + typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { + uint16 path_id; + uint32 interval_seconds; + uint8 padding[70]; + } secip_psup_req; typedef [nodiscriminant,public,flag(LIBNDR_FLAG_NOALIGN)] union { [case(SECIP_MSG_ATE_ENC)] secip_ate_enc ate_enc; [case(SECIP_MSG_PPK_COM)] secip_ppk_com ppk_com; [case(SECIP_MSG_PPK_REP)] secip_ppk_rep ppk_rep; [case(SECIP_MSG_ARC_ENC)] secip_arc_enc arc_enc; + [case(SECIP_MSG_PATH_SUPERVISION_REQUEST)] secip_psup_req psup_req; } secip_msg_union; typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { @@ -82,25 +88,17 @@ interface secip uint16 sequence_number; char device_id[16]; [switch_is(message_id)] secip_msg_union msg; - uint8 padding[30]; /* random */ } secip_packet; typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { - uint16 connection_id; /* 0xffff is unassigned */ - secip_message message_id; - uint16 sequence_number; - char device_id[16]; - [switch_is(message_id)] secip_msg_union msg; - uint8 padding[30]; /* random */ - } secip_out_packet; - - typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { - uint8 raw_packet[256]; + uint8 raw_packet[226]; + uint8 padding[30]; [value(calculate_crc(raw_packet, 256))] uint16 crc; } secip_setup_packet; typedef [public,flag(LIBNDR_FLAG_NOALIGN)] struct { - uint8 raw_packet[128]; + uint8 raw_packet[98]; + uint8 padding[30]; [value(calculate_crc(raw_packet, 128))] uint16 crc; } secip_comm_packet; }; diff --git a/secipd.c b/secipd.c index 067b2ab..0dc1367 100644 --- a/secipd.c +++ b/secipd.c @@ -4,7 +4,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or + the Free Software Foundation; either version 4 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,56 +17,177 @@ */ #include "includes.h" #include "build/ndr_secip.h" +#include + +/* FIXME Does not handle multiple connections.. should be per connection obviously!! */ +static uint8_t global_aes_key[16]; static STATUS send_ppk_com(TALLOC_CTX *mem_ctx, int sock, struct sockaddr_in from, struct secip_packet *pkt) { struct secip_setup_packet *setup_pkt; - struct secip_out_packet *ppk_com; + struct secip_packet *ppk_com; DATA_BLOB raw_pkt, raw_setup_pkt; enum ndr_err_code ndr_err; - size_t n; + size_t n, i; size_t count; const configuration *conf = get_conf(); - setup_pkt = talloc_zero(mem_ctx, struct secip_setup_packet); + setup_pkt = talloc(mem_ctx, struct secip_setup_packet); - ppk_com = talloc_zero(setup_pkt, struct secip_out_packet); - ppk_com->connection_id = pkt->connection_id; + ppk_com = talloc(setup_pkt, struct secip_packet); + ppk_com->pad = 0; + ppk_com->connection_id = 0x1337; ppk_com->message_id = SECIP_MSG_PPK_COM; ppk_com->sequence_number = 1; - memcpy(ppk_com->device_id, "MyFirstAlarm[TM]", strlen("MyFirstAlarm[TM]")); ppk_com->msg.ppk_com.session_id = 0; - mpz_export(&ppk_com->msg.ppk_com.rsa_key, &count, 1, 4, 1, 0, conf->public_key->n); + /* Device ID must not be readable at this stage */ + for (i = 0; i < 16; i++) { + ppk_com->device_id[i] = rand(); + } + for (i = 0; i < 74; i++) { + ppk_com->msg.ppk_com.padding[i] = rand(); + } + + mpz_export(&ppk_com->msg.ppk_com.rsa_key, &count, -1, 1, -1, 0, conf->public_key->n); DEBUG(0, "RSA Words written: %u", count); - printf("%s\n", ndr_print_struct_string(pkt,(ndr_print_fn_t)ndr_print_secip_out_packet, "ppk_com packet", ppk_com)); + printf("%s\n", ndr_print_struct_string(pkt,(ndr_print_fn_t)ndr_print_secip_packet, "ppk_com packet", ppk_com)); - ndr_err = ndr_push_struct_blob(&raw_pkt, ppk_com, ppk_com, (ndr_push_flags_fn_t)ndr_push_secip_out_packet); + ndr_err = ndr_push_struct_blob(&raw_pkt, ppk_com, ppk_com, (ndr_push_flags_fn_t)ndr_push_secip_packet); if (ndr_err != NDR_ERR_SUCCESS) { - DEBUG(0, "Oh holy shitstorm! That didn't work!\n"); + DEBUG(0, "Oh holy shitstorm! That didn't work!"); return ST_GENERAL_FAILURE; } memcpy(setup_pkt->raw_packet, raw_pkt.data, raw_pkt.length); + for (i = 0; i < 30; i++) { + setup_pkt->padding[i] = rand(); + } ndr_err = ndr_push_struct_blob(&raw_setup_pkt, setup_pkt, setup_pkt, (ndr_push_flags_fn_t)ndr_push_secip_setup_packet); if (ndr_err != NDR_ERR_SUCCESS) { - DEBUG(0, "Oh holy shitstorm! That didn't work!\n"); + DEBUG(0, "Oh holy shitstorm! That didn't work!"); return ST_GENERAL_FAILURE; } n = sendto(sock, raw_setup_pkt.data, raw_setup_pkt.length, 0, (struct sockaddr *)&from, sizeof(from)); - talloc_free(setup_pkt); return 0; } +static STATUS send_arc_enc(TALLOC_CTX *mem_ctx, int sock, struct sockaddr_in from, struct secip_packet *pkt) { + struct secip_setup_packet *setup_pkt; + struct secip_packet *arc_enc; + DATA_BLOB raw_pkt, raw_setup_pkt, crypted_setup_pkt; + size_t n, i; + enum ndr_err_code ndr_err; + struct aes_ctx aes; + + aes_set_encrypt_key(&aes, 16, pkt->msg.ppk_rep.key_block.aes_key); + + /* FIXME DEATH TO THE GLOBALS! */ + memcpy(global_aes_key, pkt->msg.ppk_rep.key_block.aes_key, 16); + + setup_pkt = talloc(mem_ctx, struct secip_setup_packet); + + arc_enc = talloc_zero(setup_pkt, struct secip_packet); + arc_enc->pad = 0; + arc_enc->connection_id = 0x1337; + arc_enc->message_id = SECIP_MSG_ARC_ENC; + arc_enc->sequence_number = 2; + + arc_enc->msg.arc_enc.error_code = SECIP_ERR_SUCCESS; + arc_enc->msg.arc_enc.session_id = pkt->msg.ppk_com.session_id; + + for (i = 0; i < 231; i++) { + arc_enc->msg.arc_enc.padding[i] = rand(); + } + + printf("%s\n", ndr_print_struct_string(mem_ctx, (ndr_print_fn_t)ndr_print_secip_packet, "arc_enc packet", arc_enc)); + + ndr_err = ndr_push_struct_blob(&raw_pkt, arc_enc, arc_enc, (ndr_push_flags_fn_t)ndr_push_secip_packet); + + if (ndr_err != NDR_ERR_SUCCESS) { + DEBUG(0, "Oh holy shitstorm! That didn't work!"); + return ST_GENERAL_FAILURE; + } + + memcpy(setup_pkt->raw_packet, raw_pkt.data, raw_pkt.length); + for (i = 0; i < 30; i++) { + setup_pkt->padding[i] = rand(); + } + + ndr_err = ndr_push_struct_blob(&raw_setup_pkt, setup_pkt, setup_pkt, (ndr_push_flags_fn_t)ndr_push_secip_setup_packet); + + if (ndr_err != NDR_ERR_SUCCESS) { + DEBUG(0, "Oh holy shitstorm! That didn't work!"); + return ST_GENERAL_FAILURE; + } + + crypted_setup_pkt.data = talloc_zero_array(mem_ctx, uint8_t, 258); + crypted_setup_pkt.length = 258; + memcpy(crypted_setup_pkt.data, raw_setup_pkt.data, 2); + + aes_encrypt(&aes, raw_setup_pkt.length-2, crypted_setup_pkt.data+2, raw_setup_pkt.data+2); + + n = sendto(sock, crypted_setup_pkt.data, crypted_setup_pkt.length, 0, (struct sockaddr *)&from, sizeof(from)); + + return ST_OK; +} + +DATA_BLOB decrypt_setup_packet(TALLOC_CTX *mem_ctx, DATA_BLOB encrypted_blob) { + const configuration *conf = get_conf(); + mpz_t encrypted_data; + mpz_t decrypted_data; + DATA_BLOB decrypted_blob; + int pos; + size_t length = 1; + + decrypted_blob.length = 258; + decrypted_blob.data = talloc_zero_array(mem_ctx, uint8_t, 258); + memcpy(decrypted_blob.data, encrypted_blob.data, 0x02); + + + for (pos = 0x02; pos < 258; pos += 128) { + /* Initialize the big numbers */ + mpz_init(encrypted_data); + mpz_init(decrypted_data); + + /* Do not decrypt the CRC and the connection ID */ + mpz_import(encrypted_data, 1, 1, 128, 1, 0, encrypted_blob.data + pos); + + rsa_compute_root(conf->private_key, decrypted_data, encrypted_data); + + mpz_export(decrypted_blob.data + pos, &length, 1, 128, 1, 0, decrypted_data); + } + + + return decrypted_blob; +} + +DATA_BLOB decrypt_aes_packet(TALLOC_CTX *mem_ctx, DATA_BLOB encrypted_blob) { + static DATA_BLOB ret; + struct aes_ctx aes; + + + ret.length = encrypted_blob.length; + ret.data = talloc_zero_array(mem_ctx, uint8_t, ret.length); + memcpy(ret.data, encrypted_blob.data, 2); + + aes_set_decrypt_key(&aes, 16, global_aes_key); + + aes_decrypt(&aes, encrypted_blob.length-2, ret.data+2, encrypted_blob.data+2); + + DEBUG(0, "Decrypted this packet maybe!"); + return ret; +} + int main (int argc, char **argv) { int sock, n; @@ -141,13 +262,13 @@ int main (int argc, char **argv) { while (1) { uint16_t src_port; struct secip_setup_packet *setup_pkt; + struct secip_comm_packet *comm_pkt; struct secip_packet *pkt; char buf[1024]; /* Purposefully static length */ enum ndr_err_code ndr_err; DATA_BLOB data; - setup_pkt = talloc(mem_ctx, struct secip_setup_packet); - pkt = talloc(setup_pkt, struct secip_packet); + pkt = talloc(mem_ctx, struct secip_packet); n = recvfrom(sock, &buf, sizeof(buf), 0, (struct sockaddr *) &from, &fromlen); if (n < 0) { @@ -158,22 +279,46 @@ int main (int argc, char **argv) { continue; } src_port = ntohs(from.sin_port); + DEBUG(3, "Received packet with len %d from %u", n, src_port); /* Copy packet to data blob */ data.length = n; - data.data = talloc_memdup(setup_pkt, buf, n); - - /* Parse the header */ - ndr_err = ndr_pull_struct_blob_all(&data, setup_pkt, setup_pkt, (ndr_pull_flags_fn_t)ndr_pull_secip_setup_packet); - - if (ndr_err != NDR_ERR_SUCCESS) { - DEBUG(0, "Could not parse this CRC packet"); - } - printf("%s\n", ndr_print_struct_string(setup_pkt,(ndr_print_fn_t)ndr_print_secip_setup_packet, "setup packet", setup_pkt)); - - /* Copy packet to data blob */ - data.length = data.length - sizeof(uint16_t); data.data = talloc_memdup(pkt, buf, n); + + if (*(uint16_t *)data.data < 0xFF00 && data.length > 256) { + data = decrypt_setup_packet(pkt, data); + if (data.length == 0) { + DEBUG(0, "RSA decryption failed, freeing up memory"); + talloc_free(pkt); + continue; + } + } else if (*(uint16_t *)data.data < 0xFF00 && data.length > 128) { + data = decrypt_aes_packet(pkt, data); + if (data.length == 0) { + DEBUG(0, "AES decryption failed, freeing up memory"); + talloc_free(pkt); + continue; + } + } + + /* Parse the header */ + if (data.length > 256) { + setup_pkt = talloc(pkt, struct secip_setup_packet); + ndr_err = ndr_pull_struct_blob_all(&data, pkt, setup_pkt, (ndr_pull_flags_fn_t)ndr_pull_secip_setup_packet); + + if (ndr_err != NDR_ERR_SUCCESS) { + DEBUG(0, "Could not parse this CRC packet"); + } + printf("%s\n", ndr_print_struct_string(setup_pkt,(ndr_print_fn_t)ndr_print_secip_setup_packet, "setup packet", setup_pkt)); + } else if (data.length > 128) { + comm_pkt = talloc(pkt, struct secip_comm_packet); + ndr_err = ndr_pull_struct_blob_all(&data, pkt, comm_pkt, (ndr_pull_flags_fn_t)ndr_pull_secip_comm_packet); + + if (ndr_err != NDR_ERR_SUCCESS) { + DEBUG(0, "Could not parse this CRC packet"); + } + printf("%s\n", ndr_print_struct_string(comm_pkt,(ndr_print_fn_t)ndr_print_secip_comm_packet, "comm packet", comm_pkt)); + } ndr_err = ndr_pull_struct_blob_all(&data, pkt, pkt, (ndr_pull_flags_fn_t)ndr_pull_secip_packet); @@ -182,12 +327,16 @@ int main (int argc, char **argv) { } printf("%s\n", ndr_print_struct_string(pkt,(ndr_print_fn_t)ndr_print_secip_packet, "packet", pkt)); - DEBUG(0, "%x %x %x %x", pkt->connection_id, pkt->message_id, pkt->sequence_number); + DEBUG(0, "%x %x %x", pkt->connection_id, pkt->message_id, pkt->sequence_number); if (pkt->message_id == SECIP_MSG_ATE_ENC && pkt->msg.ate_enc.session_id == 0x0000) { send_ppk_com(pkt, sock, from, pkt); } - DEBUG(3, "Received packet with len %d from %u", n, src_port); - talloc_free(setup_pkt); + if (pkt->message_id == SECIP_MSG_PPK_REP) { + send_arc_enc(pkt, sock, from, pkt); + } + + + talloc_free(pkt); } } diff --git a/siahs.h b/siahs.h index 6ba8b7b..e15f894 100644 --- a/siahs.h +++ b/siahs.h @@ -31,4 +31,36 @@ struct siahs_packet { uint16_t checksum; }; - +const uint8_t xor_table[] = { 0x51, 0x7a, 0x26, 0x3d, 0x22, 0x21, 0x3b, 0x74, + 0x31, 0x30, 0x74, 0x27, 0x3b, 0x30, 0x3d, 0x22, + 0x21, 0x3b, 0x74, 0x27, 0x3b, 0x74, 0x39, 0x31, + 0x3c, 0x37, 0x3a, 0x31, 0x74, 0x31, 0x27, 0x74, + 0x39, 0x31, 0x3a, 0x74, 0x78, 0x26, 0x31, 0x22, + 0x74, 0x31, 0x30, 0x74, 0x39, 0x35, 0x20, 0x26, + 0x35, 0x32, 0x74, 0x31, 0x27, 0x74, 0x3b, 0xb7, + 0x3a, 0x74, 0x27, 0x3b, 0x3c, 0x38, 0x3b, 0x74, + 0x27, 0x3b, 0x6f, 0xc1, 0x26, 0x3d, 0x39, 0x3d, + 0x26, 0x24, 0x2c, 0x31, 0x74, 0x31, 0x30, 0x3b, + 0x24, 0x74, 0x27, 0x35, 0x74, 0x39, 0xbd, 0x21, + 0x33, 0x3a, 0x3d, 0x3a, 0x74, 0x31, 0x21, 0x25, + 0x74, 0x78, 0x27, 0x3d, 0x35, 0x20, 0x74, 0x27, + 0x35, 0x26, 0x3d, 0x31, 0x27, 0x3a, 0x35, 0x37, + 0x74, 0x3b, 0xb7, 0x27, 0x74, 0x27, 0x35, 0x27, + 0x3d, 0x3b, 0x37, 0x74, 0x27, 0x35, 0x74, 0x27, + 0x35, 0x30, 0x3b, 0x00, 0xfb, 0x7a, 0x26, 0x31, + 0x26, 0x26, 0x3b, 0x37, 0x74, 0x35, 0x74, 0x27, + 0x31, 0x38, 0x31, 0x74, 0x39, 0x35, 0x3a, 0x26, + 0x3b, 0x20, 0x74, 0xb5, 0x38, 0x74, 0x35, 0x26, + 0x35, 0x24, 0x74, 0x78, 0x27, 0x3b, 0x3d, 0x26, + 0x74, 0x27, 0x3b, 0x74, 0x39, 0x31, 0x26, 0x26, + 0x3b, 0x37, 0x74, 0x31, 0x30, 0x3a, 0x3b, 0x74, + 0x35, 0x26, 0x35, 0x24, 0x74, 0x26, 0x35, 0x33, + 0x21, 0x38, 0x74, 0x3b, 0x35, 0x9a, 0x6f, 0x31, + 0x3c, 0x37, 0x3a, 0x31, 0x74, 0x31, 0x27, 0x74, + 0x3b, 0xb7, 0x3a, 0x74, 0x26, 0x35, 0x39, 0x74, + 0x3b, 0x74, 0x31, 0x74, 0x78, 0x26, 0x35, 0x39, + 0x74, 0x3b, 0x74, 0x35, 0x26, 0x35, 0x24, 0x74, + 0x39, 0x31, 0x26, 0x26, 0x3b, 0x37, 0x74, 0x27, + 0x3b, 0x3d, 0x26, 0x74, 0x27, 0x3b, 0x74, 0x27, + 0x3b, 0x30, 0x3b, 0x00, 0xaa, 0x11, 0x46, 0x54, +}; diff --git a/wscript b/wscript index 1d95917..bf00201 100644 --- a/wscript +++ b/wscript @@ -84,7 +84,7 @@ def configure(conf): conf.check_cc(lib='gmp', uselib_store='nettle') # Purposefully at the bottom because waf configuration tests fail with -Wstrict-prototypes and -Werror - conf.env.CFLAGS = ['-O2', '-g', '-ggdb', '-std=c99', '-Wall', '-Wshadow', '-Wpointer-arith', '-Wcast-align', '-Wwrite-strings', '-Wdeclaration-after-statement', + conf.env.CFLAGS = ['-O0', '-g', '-ggdb', '-std=c99', '-Wall', '-Wshadow', '-Wpointer-arith', '-Wcast-align', '-Wwrite-strings', '-Wdeclaration-after-statement', '-Werror-implicit-function-declaration', '-Wstrict-prototypes', '-Werror'] def build(bld):