Browse Source

Add support for EMM reassemblation.

OSCAM does the reassemblation only when the input is dvbapi.
This means that a client (like tsdecrypt) that uses network
protocol must do EMM reassembly by itself. This commit adds
reassembly support for Cryptoworks and Viaccess CA systems.

The card update was tested and found to be working on Swiss
Viaccess cards.
Georgi Chorbadzhiyski 11 years ago
parent
commit
1f098d65b1
10 changed files with 287 additions and 4 deletions
  1. 2
    0
      ChangeLog
  2. 1
    0
      Makefile
  3. 1
    0
      README
  4. 2
    0
      data.c
  5. 3
    0
      data.h
  6. 212
    0
      fixups.c
  7. 23
    0
      fixups.h
  8. 8
    0
      tables.c
  9. 7
    0
      tsdecrypt.1
  10. 28
    4
      tsdecrypt.c

+ 2
- 0
ChangeLog View File

@@ -17,6 +17,8 @@
17 17
    Now file:// prefix is must be added before the filename otherwise
18 18
    the parameter is treated as network address.
19 19
  * Add --emm-filter (-a) option. This option implements EMM filtering.
20
+ * Add EMM reassembly (fixups) for Cryptoworks and Viaccess. The fixups
21
+   are enabled by default and can be disabled by --no-emm-fixups (-q).
20 22
 
21 23
 2012-04-19 : Version 8.1
22 24
  * Add support for Bulcrypt CAS.

+ 1
- 0
Makefile View File

@@ -42,6 +42,7 @@ tsdecrypt_SRC = data.c \
42 42
  udp.c \
43 43
  util.c \
44 44
  filter.c \
45
+ fixups.c \
45 46
  camd.c \
46 47
  camd-cs378x.c \
47 48
  camd-newcamd.c \

+ 1
- 0
README View File

@@ -171,6 +171,7 @@ EMM options:
171 171
  -a --emm-filter <filter>   | Add EMM filter defined by <filter>.
172 172
                             . This option can be used multiple times (max:16).
173 173
                             . See FILTERING file for more info.
174
+ -q --no-emm-fixups         | Disable EMM fixups for CRYPTOWORKS and VIACCESS.
174 175
 
175 176
 ECM options:
176 177
  -X --ecm-pid <pid>         | Force ECM pid. Default: none

+ 2
- 0
data.c View File

@@ -75,6 +75,8 @@ void data_init(struct ts *ts) {
75 75
 	ts->emm_send    = 0;
76 76
 	ts->pid_filter  = 1;
77 77
 
78
+	ts->emm_fixups  = 1;
79
+
78 80
 	ts->emm_report_interval = 60;
79 81
 	ts->emm_last_report     = time(NULL);
80 82
 

+ 3
- 0
data.h View File

@@ -318,6 +318,9 @@ struct ts {
318 318
 
319 319
 	int					emm_filters_num;
320 320
 	struct filter		emm_filters[MAX_FILTERS];
321
+
322
+	int					emm_fixups;
323
+	int					(*emm_fixup_func)(uint8_t *buffer, unsigned int *len);
321 324
 };
322 325
 
323 326
 void data_init(struct ts *ts);

+ 212
- 0
fixups.c View File

@@ -0,0 +1,212 @@
1
+/*
2
+ * CA system specific fixups
3
+ * Copyright (C) 2010-2012 OSCAM Developers.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License (COPYING file) for more details.
13
+ *
14
+ */
15
+#include <stdio.h>
16
+#include <stdarg.h>
17
+#include <string.h>
18
+#include <inttypes.h>
19
+
20
+#include "libtsfuncs/tsfuncs.h"
21
+
22
+#include "fixups.h"
23
+
24
+static int DEBUG = 0;
25
+
26
+static uint8_t emm_global[1024];
27
+static int emm_global_len = 0;
28
+
29
+static void ts_LOGf_hd(uint8_t *buf, int len, const char *fmt, ...) {
30
+	if (!DEBUG)
31
+		return;
32
+	char msg[1024];
33
+	char msg2[1024];
34
+	unsigned int i;
35
+	va_list args;
36
+	va_start(args, fmt);
37
+	vsnprintf(msg, sizeof(msg)-1, fmt, args);
38
+	va_end(args);
39
+	msg[sizeof(msg)-2] = '\n';
40
+	msg[sizeof(msg)-1] = '\0';
41
+	ts_hex_dump_buf(msg2, sizeof(msg2), buf, len, 16);
42
+	for (i = 0; i < strlen(msg); i++) {
43
+		if (msg[i] == '\n')
44
+			msg[i] = ' ';
45
+	}
46
+	ts_LOGf("XXX: %s, len: %d:\n%s\n", msg, len, msg2);
47
+}
48
+
49
+#define dbg_ts_LOGf_hd(...) \
50
+	do { if (DEBUG) ts_LOGf_hd(__VA_ARGS__); } while (0)
51
+
52
+#define dbg_ts_LOGf(...) \
53
+	do { if (DEBUG) ts_LOGf(__VA_ARGS__); } while (0)
54
+
55
+static void sort_nanos(unsigned char *dest, const unsigned char *src, int src_len) {
56
+	int dst_pos = 0, marker = -1, src_pos, nano, nano_len;
57
+	do {
58
+		nano = 0x100;
59
+		for (src_pos = 0; src_pos < src_len; ) {
60
+			nano_len = src[src_pos + 1] + 2;
61
+			if (src[src_pos] == marker) {
62
+				if (dst_pos + nano_len > src_len) {
63
+					// ERROR
64
+					memset(dest, 0, src_len);
65
+					return;
66
+				}
67
+				memcpy(dest + dst_pos, src + src_pos, nano_len);
68
+				dst_pos += nano_len;
69
+			} else if (src[src_pos] > marker && src[src_pos] < nano) {
70
+				nano = src[src_pos];
71
+			}
72
+			src_pos += nano_len;
73
+		}
74
+		if (nano >= 0x100)
75
+			break;
76
+		marker = nano;
77
+	} while (1);
78
+}
79
+
80
+
81
+int viaccess_reassemble_emm(uint8_t *buffer, unsigned int *len) {
82
+	if (*len > 500)
83
+		return 0;
84
+
85
+	switch (buffer[0]) {
86
+	case 0x8c:
87
+	case 0x8d: { // emm-s part 1
88
+		if (!memcmp(emm_global, buffer, *len))
89
+			return 0;
90
+		// copy first part of the emm-s
91
+		memcpy(emm_global, buffer, *len);
92
+		emm_global_len = *len;
93
+		dbg_ts_LOGf_hd(buffer, *len, "viaccess global emm:\n");
94
+		return 0;
95
+	}
96
+	case 0x8e: { // emm-s part 2
97
+		if (!emm_global_len)
98
+			return 0;
99
+
100
+		int i, pos = 0;
101
+		unsigned int k;
102
+
103
+		// extract nanos from emm-gh and emm-s
104
+		uint8_t emmbuf[1024];
105
+
106
+		dbg_ts_LOGf("[viaccess] %s: start extracting nanos\n", __func__);
107
+		// extract from emm-gh
108
+		for (i = 3; i < emm_global_len; i += emm_global[i+1] + 2) {
109
+			//copy nano (length determined by i+1)
110
+			memcpy(emmbuf + pos, emm_global+i, emm_global[i+1] + 2);
111
+			pos += emm_global[i+1] + 2;
112
+		}
113
+
114
+		if (buffer[2] == 0x2c) {
115
+			// Add 9E 20 nano + first 32 bytes of emm content
116
+			memcpy(emmbuf+pos, "\x9E\x20", 2);
117
+			memcpy(emmbuf+pos+2, buffer+7, 32);
118
+			pos += 34;
119
+
120
+			//add F0 08 nano + 8 subsequent bytes of emm content
121
+			memcpy(emmbuf+pos, "\xF0\x08", 2);
122
+			memcpy(emmbuf+pos+2, buffer+39, 8);
123
+			pos += 10;
124
+		} else {
125
+			// Extract from variable emm-s
126
+			for (k = 7; k < (*len); k += buffer[k+1]+2) {
127
+				// Copy nano (length determined by k+1)
128
+				memcpy(emmbuf + pos, buffer + k, buffer[k + 1] + 2);
129
+				pos += buffer[k + 1] + 2;
130
+			}
131
+		}
132
+
133
+		dbg_ts_LOGf_hd(buffer, *len, "[viaccess] %s: %s emm-s\n", __func__, (buffer[2]==0x2c) ? "fixed" : "variable");
134
+
135
+		sort_nanos(buffer + 7, emmbuf, pos);
136
+		pos += 7;
137
+
138
+		// Calculate emm length and set it on position 2
139
+		buffer[2] = pos - 3;
140
+
141
+		dbg_ts_LOGf_hd(emm_global, emm_global_len, "[viaccess] %s: emm-gh\n", __func__);
142
+		dbg_ts_LOGf_hd(buffer    , pos           , "[viaccess] %s: assembled emm\n", __func__);
143
+
144
+		*len = pos;
145
+		break;
146
+	}
147
+	}
148
+	return 1;
149
+}
150
+
151
+int cryptoworks_reassemble_emm(uint8_t *buffer, unsigned int *len) {
152
+	if (*len > 500)
153
+		return 0;
154
+
155
+	// Cryptoworks
156
+	//   Cryptoworks EMM-S have to be assembled by the client from an EMM-SH with table
157
+	//   id 0x84 and a corresponding EMM-SB (body) with table id 0x86. A pseudo EMM-S
158
+	//   with table id 0x84 has to be build containing all nano commands from both the
159
+	//    original EMM-SH and EMM-SB in ascending order.
160
+	//
161
+	switch (buffer[0]) {
162
+	case 0x84: { // emm-sh
163
+		if (memcmp(emm_global, buffer, *len) == 0)
164
+			return 0;
165
+		memcpy(emm_global, buffer, *len);
166
+		emm_global_len = *len;
167
+		return 0;
168
+	}
169
+	case 0x86: { // emm-sb
170
+		dbg_ts_LOGf_hd(buffer, *len, "[cryptoworks] shared emm (EMM-SB) /ORG/\n");
171
+		if (!emm_global_len) {
172
+			dbg_ts_LOGf("[cryptoworks] no 84 part yet.\n");
173
+			return 0;
174
+		}
175
+		// We keep the first 12 bytes of the 0x84 emm (EMM-SH)
176
+		// now we need to append the payload of the 0x86 emm (EMM-SB)
177
+		// starting after the header (&buffer[5])
178
+		// then the rest of the payload from EMM-SH
179
+		// so we should have :
180
+		// EMM-SH[0:12] + EMM-SB[5:len_EMM-SB] + EMM-SH[12:EMM-SH_len]
181
+		// then sort the nano in ascending order
182
+		// update the emm len (emmBuf[1:2])
183
+		//
184
+		int emm_len = *len - 5 + emm_global_len - 12;
185
+		uint8_t tmp[emm_len];
186
+		uint8_t assembled_EMM[emm_len + 12];
187
+		memcpy(tmp, &buffer[5], *len - 5);
188
+		memcpy(tmp + *len - 5, &emm_global[12], emm_global_len - 12);
189
+		memcpy(assembled_EMM, emm_global, 12);
190
+		sort_nanos(assembled_EMM + 12, tmp, emm_len);
191
+
192
+		assembled_EMM[1] = ((emm_len + 9) >> 8) | 0x70;
193
+		assembled_EMM[2] = (emm_len + 9) & 0xFF;
194
+
195
+		// Copy back the assembled emm in the working buffer
196
+		memcpy(buffer, assembled_EMM, emm_len + 12);
197
+		*len = emm_len + 12;
198
+
199
+		emm_global_len = 0;
200
+
201
+		dbg_ts_LOGf_hd(buffer, emm_len + 12, "[cryptoworks] shared emm (assembled)\n");
202
+		if (assembled_EMM[11] != emm_len) { // sanity check
203
+			// error in emm assembly
204
+			dbg_ts_LOGf("[cryptoworks] Error assembling Cryptoworks EMM-S %d != %d\n", assembled_EMM[11], emm_len);
205
+			return 0;
206
+		}
207
+		break;
208
+	}
209
+	}
210
+
211
+	return 1;
212
+}

+ 23
- 0
fixups.h View File

@@ -0,0 +1,23 @@
1
+/*
2
+ * CA system specific fixups
3
+ * Copyright (C) 2010-2012 OSCAM Developers.
4
+ *
5
+ * This program is free software; you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License (COPYING file) for more details.
13
+ *
14
+ */
15
+#ifndef FIXUPS_H
16
+#define FIXUPS_H
17
+
18
+#include <inttypes.h>
19
+
20
+int viaccess_reassemble_emm(uint8_t *buffer, unsigned int *len);
21
+int cryptoworks_reassemble_emm(uint8_t *buffer, unsigned int *len);
22
+
23
+#endif

+ 8
- 0
tables.c View File

@@ -288,6 +288,14 @@ static void __process_emm(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
288 288
 	if (ts->emm_filters_num)
289 289
 		emm_ok = filter_match_emm(ts, sec->section_data, sec->section_data_len);
290 290
 
291
+	if (emm_ok && ts->emm_fixup_func) {
292
+		unsigned int len = sec->section_data_len;
293
+		if (ts->emm_fixup_func(sec->section_data, &len)) {
294
+			//ts_LOGf("EMM | Reassembled EMM, old len: %d, new len:%d\n", sec->section_data_len, len);
295
+			sec->section_data_len = len;
296
+		}
297
+	}
298
+
291 299
 	if (ts->debug_level >= 2) {
292 300
 		ts_hex_dump_buf(dump, dump_buf_sz, sec->section_data, min(dump_sz, sec->section_data_len), 0);
293 301
 		ts_LOGf("EMM | SID 0x%04x CAID: 0x%04x PID 0x%04x Table: 0x%02x Length: %4d %s %s..\n",

+ 7
- 0
tsdecrypt.1 View File

@@ -241,6 +241,13 @@ For more information about filtering and for example filters, please
241 241
 read \fBFILTERING\fR file that comes with tsdecrypt. This option can be
242 242
 used multiple times to define up to \fB16\fR different filters.
243 243
 .TP
244
+\fB\-q\fR, \fB\-\-no\-emm\-fixups\fR
245
+Disable fixups that are applied to Cryptoworks and Viaccess EMMs.
246
+
247
+These fixups add and reorder needed nanos in the EMM so OSCAM can
248
+write the EMM into the card. Without EMM fixups some cards can't
249
+be updated, thats why the fixups are enabled by default.
250
+.TP
244 251
 .SH ECM OPTIONS
245 252
 .PP
246 253
 .TP

+ 28
- 4
tsdecrypt.c View File

@@ -36,6 +36,7 @@
36 36
 #include "udp.h"
37 37
 #include "notify.h"
38 38
 #include "filter.h"
39
+#include "fixups.h"
39 40
 
40 41
 #define FIRST_REPORT_SEC 3
41 42
 
@@ -79,9 +80,9 @@ static void LOG_func(const char *msg) {
79 80
 		LOG(msg);
80 81
 }
81 82
 
82
-static const char short_options[] = "i:d:N:Sl:L:F:I:RzM:T:W:O:o:t:rk:g:upwxyc:C:Y:Q:A:s:U:P:B:46eZ:Ef:a:X:H:G:KJ:D:jbhVn:m:";
83
+static const char short_options[] = "i:d:N:Sl:L:F:I:RzM:T:W:O:o:t:rk:g:upwxyc:C:Y:Q:A:s:U:P:B:46eZ:Ef:a:X:H:G:KJ:D:jbhVn:m:q";
83 84
 
84
-// Unused short options: aqv01235789
85
+// Unused short options: av01235789
85 86
 static const struct option long_options[] = {
86 87
 	{ "ident",				required_argument, NULL, 'i' },
87 88
 	{ "daemon",				required_argument, NULL, 'd' },
@@ -128,6 +129,7 @@ static const struct option long_options[] = {
128 129
 	{ "emm-only",			no_argument,       NULL, 'E' },
129 130
 	{ "emm-report-time",	required_argument, NULL, 'f' },
130 131
 	{ "emm-filter",			required_argument, NULL, 'a' },
132
+	{ "no-emm-fixups",		no_argument,       NULL, 'q' },
131 133
 
132 134
 	{ "ecm-pid",			required_argument, NULL, 'X' },
133 135
 	{ "ecm-report-time",	required_argument, NULL, 'H' },
@@ -228,6 +230,7 @@ static void show_help(struct ts *ts) {
228 230
 	printf(" -a --emm-filter <filter>   | Add EMM filter defined by <filter>.\n");
229 231
 	printf("                            . This option can be used multiple times (max:%u).\n", MAX_FILTERS);
230 232
 	printf("                            . See FILTERING file for more info.\n");
233
+	printf(" -q --no-emm-fixups         | Disable EMM fixups for CRYPTOWORKS and VIACCESS.");
231 234
 	printf("\n");
232 235
 	printf("ECM options:\n");
233 236
 	printf(" -X --ecm-pid <pid>         | Force ECM pid. Default: none\n");
@@ -521,6 +524,10 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
521 524
 				}
522 525
 				break;
523 526
 
527
+			case 'q': // --no-emm-fixups
528
+				ts->emm_fixups = !ts->emm_fixups;
529
+				break;
530
+
524 531
 			case 'X': // --ecm-pid
525 532
 				ts->forced_ecm_pid = strtoul(optarg, NULL, 0) & 0x1fff;
526 533
 				break;
@@ -685,6 +692,19 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
685 692
 		ts_LOGf("Constant CW: odd  = %s\n", cw_odd);
686 693
 	}
687 694
 
695
+	if (ts->emm_fixups) {
696
+		switch (ts->req_CA_sys) {
697
+			case CA_CRYPTOWORKS:
698
+				ts->emm_fixup_func = cryptoworks_reassemble_emm;
699
+				break;
700
+			case CA_VIACCESS:
701
+				ts->emm_fixup_func = viaccess_reassemble_emm;
702
+				break;
703
+			default:
704
+				ts->emm_fixups = 0;
705
+		}
706
+	}
707
+
688 708
 	if (ts->input.type == NET_IO) {
689 709
 		ts_LOGf("Input addr : %s://%s:%s/\n",
690 710
 			ts->rtp_input ? "rtp" : "udp",
@@ -777,11 +797,15 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
777 797
 			ts_LOGf("EMM pid    : 0x%04x (%d)\n", ts->forced_emm_pid, ts->forced_emm_pid);
778 798
 	}
779 799
 	if (ts->emm_only) {
780
-		ts_LOGf("EMM only   : %s\n", ts->emm_only ? "yes" : "no");
800
+		ts_LOGf("EMM only   : %s%s\n",
801
+			ts->emm_only ? "yes" : "no",
802
+			ts->emm_fixups ? " +fixups" : "");
781 803
 	} else {
782 804
 		if (!packet_from_file) {
783 805
 			if (!ts->camd.constant_codeword)
784
-				ts_LOGf("EMM send   : %s\n", ts->emm_send   ? "enabled" : "disabled");
806
+				ts_LOGf("EMM sending: %s%s\n",
807
+					ts->emm_send ? "yes" : "no",
808
+					ts->emm_send && ts->emm_fixups ? " +fixups" : "");
785 809
 			ts_LOGf("Decoding   : %s\n", ts->threaded ? "threaded" : "single thread");
786 810
 		}
787 811
 	}

Loading…
Cancel
Save