[PR-54] Switch to libdvbcsa: update code word client and campt

As libdvbcsa works on packet payloads instead of full packets, I borrowed
the packet inspection code from FFdecsa.

Tested and found working with Irdeto2 CA system and OSCam's NewCamd emulation.

As the capmt code doesn't use key change notification, there might be a race
between key updates and decryption, when there is undecrypted data batched up.
This has not been tested yet, as I don't have a capmt cardserver.
This commit is contained in:
Alain Kalker 2012-02-11 17:35:03 +01:00 committed by Adam Sutton
parent 303313a82f
commit 7c1819ba92
3 changed files with 164 additions and 60 deletions

View file

@ -42,7 +42,7 @@
#include "tcp.h"
#include "psi.h"
#include "tsdemux.h"
#include "ffdecsa/FFdecsa.h"
#include <dvbcsa/dvbcsa.h>
#include "capmt.h"
#include "notify.h"
#include "subscriptions.h"
@ -155,13 +155,18 @@ typedef struct capmt_service {
CT_FORBIDDEN
} ct_keystate;
/* buffer for keystruct */
void *ct_keys;
/* buffers for keystructs */
struct dvbcsa_bs_key_s *ct_key_even;
struct dvbcsa_bs_key_s *ct_key_odd;
/* CSA */
int ct_cluster_size;
uint8_t *ct_tsbcluster;
struct dvbcsa_bs_batch_s *ct_tsbbatch_even;
struct dvbcsa_bs_batch_s *ct_tsbbatch_odd;
int ct_fill;
int ct_fill_even;
int ct_fill_odd;
/* current sequence number */
uint16_t ct_seq;
@ -359,7 +364,10 @@ capmt_service_destroy(th_descrambler_t *td)
LIST_REMOVE(ct, ct_link);
free_key_struct(ct->ct_keys);
dvbcsa_bs_key_free(ct->ct_key_odd);
dvbcsa_bs_key_free(ct->ct_key_even);
free(ct->ct_tsbbatch_odd);
free(ct->ct_tsbbatch_even);
free(ct->ct_tsbcluster);
free(ct);
}
@ -498,9 +506,9 @@ handle_ca0(capmt_t* capmt) {
continue;
if (memcmp(even, invalid, 8))
set_even_control_word(ct->ct_keys, even);
dvbcsa_bs_key_set(even, ct->ct_key_even);
if (memcmp(odd, invalid, 8))
set_odd_control_word(ct->ct_keys, odd);
dvbcsa_bs_key_set(odd, ct->ct_key_odd);
if(ct->ct_keystate != CT_RESOLVED)
tvhlog(LOG_INFO, "capmt", "Obtained key for service \"%s\"",t->s_svcname);
@ -839,8 +847,14 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
const uint8_t *tsb)
{
capmt_service_t *ct = (capmt_service_t *)td;
int r, i;
unsigned char *vec[3];
uint8_t *pkt;
int xc0;
int ev_od;
int len;
int offset;
int n;
// FIXME: //int residue;
int i;
uint8_t *t0;
if(ct->ct_keystate == CT_FORBIDDEN)
@ -849,28 +863,67 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
if(ct->ct_keystate != CT_RESOLVED)
return -1;
memcpy(ct->ct_tsbcluster + ct->ct_fill * 188, tsb, 188);
pkt = ct->ct_tsbcluster + ct->ct_fill * 188;
memcpy(pkt, tsb, 188);
ct->ct_fill++;
do { // handle this packet
xc0 = pkt[3] & 0xc0;
if(xc0 == 0x00) { // clear
break;
}
if(xc0 == 0x40) { // reserved
break;
}
if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
pkt[3] &= 0x3f; // consider it decrypted now
if(pkt[3] & 0x20) { // incomplete packet
offset = 4 + pkt[4] + 1;
len = 188 - offset;
n = len >> 3;
// FIXME: //residue = len - (n << 3);
if(n == 0) { // decrypted==encrypted!
break; // this doesn't need more processing
}
} else {
len = 184;
offset = 4;
// FIXME: //n = 23;
// FIXME: //residue = 0;
}
if(ev_od == 0) {
ct->ct_tsbbatch_even[ct->ct_fill_even].data = pkt + offset;
ct->ct_tsbbatch_even[ct->ct_fill_even].len = len;
ct->ct_fill_even++;
} else {
ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = pkt + offset;
ct->ct_tsbbatch_odd[ct->ct_fill_odd].len = len;
ct->ct_fill_odd++;
}
}
} while(0);
if(ct->ct_fill != ct->ct_cluster_size)
return 0;
ct->ct_fill = 0;
if(ct->ct_fill_even) {
ct->ct_tsbbatch_even[ct->ct_fill_even].data = NULL;
dvbcsa_bs_decrypt(ct->ct_key_even, ct->ct_tsbbatch_even, 184);
ct->ct_fill_even = 0;
}
if(ct->ct_fill_odd) {
ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = NULL;
dvbcsa_bs_decrypt(ct->ct_key_odd, ct->ct_tsbbatch_odd, 184);
ct->ct_fill_odd = 0;
}
vec[0] = ct->ct_tsbcluster;
vec[1] = ct->ct_tsbcluster + ct->ct_cluster_size * 188;
vec[2] = NULL;
while(1) {
t0 = vec[0];
r = decrypt_packets(ct->ct_keys, vec);
if(r == 0)
break;
for(i = 0; i < r; i++) {
t0 = ct->ct_tsbcluster;
for(i = 0; i < ct->ct_fill; i++) {
ts_recv_packet2(t, t0);
t0 += 188;
}
}
ct->ct_fill = 0;
return 0;
}
@ -898,10 +951,14 @@ capmt_service_start(service_t *t)
elementary_stream_t *st;
/* create new capmt service */
ct = calloc(1, sizeof(capmt_service_t));
ct->ct_cluster_size = get_suggested_cluster_size();
ct->ct_tsbcluster = malloc(ct->ct_cluster_size * 188);
ct->ct_seq = capmt->capmt_seq++;
ct = calloc(1, sizeof(capmt_service_t));
ct->ct_cluster_size = dvbcsa_bs_batch_size();
ct->ct_tsbcluster = malloc(ct->ct_cluster_size * 188);
ct->ct_tsbbatch_even = malloc((ct->ct_cluster_size + 1) *
sizeof(struct dvbcsa_bs_batch_s));
ct->ct_tsbbatch_odd = malloc((ct->ct_cluster_size + 1) *
sizeof(struct dvbcsa_bs_batch_s));
ct->ct_seq = capmt->capmt_seq++;
TAILQ_FOREACH(st, &t->s_components, es_link) {
caid_t *c;
@ -924,7 +981,8 @@ capmt_service_start(service_t *t)
}
}
ct->ct_keys = get_key_struct();
ct->ct_key_even = dvbcsa_bs_key_alloc();
ct->ct_key_odd = dvbcsa_bs_key_alloc();
ct->ct_capmt = capmt;
ct->ct_service = t;

112
src/cwc.c
View file

@ -31,7 +31,7 @@
#include "tcp.h"
#include "psi.h"
#include "tsdemux.h"
#include "ffdecsa/FFdecsa.h"
#include <dvbcsa/dvbcsa.h>
#include "cwc.h"
#include "notify.h"
#include "atomic.h"
@ -155,7 +155,8 @@ typedef struct cwc_service {
CS_IDLE
} cs_keystate;
void *cs_keys;
struct dvbcsa_bs_key_s *cs_key_even;
struct dvbcsa_bs_key_s *cs_key_odd;
uint8_t cs_cw[16];
@ -166,7 +167,11 @@ typedef struct cwc_service {
*/
int cs_cluster_size;
uint8_t *cs_tsbcluster;
struct dvbcsa_bs_batch_s *cs_tsbbatch_even;
struct dvbcsa_bs_batch_s *cs_tsbbatch_odd;
int cs_fill;
int cs_fill_even;
int cs_fill_odd;
LIST_HEAD(, ecm_pid) cs_pids;
@ -1884,13 +1889,13 @@ update_keys(cwc_service_t *ct)
ct->cs_pending_cw_update = 0;
for(i = 0; i < 8; i++)
if(ct->cs_cw[i]) {
set_even_control_word(ct->cs_keys, ct->cs_cw);
dvbcsa_bs_key_set(ct->cs_cw, ct->cs_key_even);
break;
}
for(i = 0; i < 8; i++)
if(ct->cs_cw[8 + i]) {
set_odd_control_word(ct->cs_keys, ct->cs_cw + 8);
dvbcsa_bs_key_set(ct->cs_cw + 8, ct->cs_key_odd);
break;
}
}
@ -1904,8 +1909,13 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
const uint8_t *tsb)
{
cwc_service_t *ct = (cwc_service_t *)td;
int r;
unsigned char *vec[3];
uint8_t *pkt;
int xc0;
int ev_od;
int len;
int offset;
int n;
// FIXME: //int residue;
if(ct->cs_keystate == CS_FORBIDDEN)
return 1;
@ -1916,42 +1926,72 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
update_keys(ct);
memcpy(ct->cs_tsbcluster + ct->cs_fill * 188, tsb, 188);
pkt = ct->cs_tsbcluster + ct->cs_fill * 188;
memcpy(pkt, tsb, 188);
ct->cs_fill++;
do { // handle this packet
xc0 = pkt[3] & 0xc0;
if(xc0 == 0x00) { // clear
break;
}
if(xc0 == 0x40) { // reserved
break;
}
if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
pkt[3] &= 0x3f; // consider it decrypted now
if(pkt[3] & 0x20) { // incomplete packet
offset = 4 + pkt[4] + 1;
len = 188 - offset;
n = len >> 3;
// FIXME: //residue = len - (n << 3);
if(n == 0) { // decrypted==encrypted!
break; // this doesn't need more processing
}
} else {
len = 184;
offset = 4;
// FIXME: //n = 23;
// FIXME: //residue = 0;
}
if(ev_od == 0) {
ct->cs_tsbbatch_even[ct->cs_fill_even].data = pkt + offset;
ct->cs_tsbbatch_even[ct->cs_fill_even].len = len;
ct->cs_fill_even++;
} else {
ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = pkt + offset;
ct->cs_tsbbatch_odd[ct->cs_fill_odd].len = len;
ct->cs_fill_odd++;
}
}
} while(0);
if(ct->cs_fill != ct->cs_cluster_size)
return 0;
while(1) {
if(ct->cs_fill_even) {
ct->cs_tsbbatch_even[ct->cs_fill_even].data = NULL;
dvbcsa_bs_decrypt(ct->cs_key_even, ct->cs_tsbbatch_even, 184);
ct->cs_fill_even = 0;
}
if(ct->cs_fill_odd) {
ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = NULL;
dvbcsa_bs_decrypt(ct->cs_key_odd, ct->cs_tsbbatch_odd, 184);
ct->cs_fill_odd = 0;
}
vec[0] = ct->cs_tsbcluster;
vec[1] = ct->cs_tsbcluster + ct->cs_fill * 188;
vec[2] = NULL;
r = decrypt_packets(ct->cs_keys, vec);
if(r > 0) {
{
int i;
const uint8_t *t0 = ct->cs_tsbcluster;
for(i = 0; i < r; i++) {
for(i = 0; i < ct->cs_fill; i++) {
ts_recv_packet2(t, t0);
t0 += 188;
}
r = ct->cs_fill - r;
assert(r >= 0);
if(r > 0)
memmove(ct->cs_tsbcluster, t0, r * 188);
ct->cs_fill = r;
if(ct->cs_pending_cw_update && r > 0)
continue;
} else {
ct->cs_fill = 0;
}
break;
}
ct->cs_fill = 0;
if(ct->cs_pending_cw_update)
update_keys(ct);
@ -1980,7 +2020,10 @@ cwc_service_destroy(th_descrambler_t *td)
LIST_REMOVE(ct, cs_link);
free_key_struct(ct->cs_keys);
dvbcsa_bs_key_free(ct->cs_key_odd);
dvbcsa_bs_key_free(ct->cs_key_even);
free(ct->cs_tsbbatch_odd);
free(ct->cs_tsbbatch_even);
free(ct->cs_tsbcluster);
free(ct);
}
@ -2025,10 +2068,15 @@ cwc_service_start(service_t *t)
continue;
ct = calloc(1, sizeof(cwc_service_t));
ct->cs_cluster_size = get_suggested_cluster_size();
ct->cs_cluster_size = dvbcsa_bs_batch_size();
ct->cs_tsbcluster = malloc(ct->cs_cluster_size * 188);
ct->cs_tsbbatch_even = malloc((ct->cs_cluster_size + 1) *
sizeof(struct dvbcsa_bs_batch_s));
ct->cs_tsbbatch_odd = malloc((ct->cs_cluster_size + 1) *
sizeof(struct dvbcsa_bs_batch_s));
ct->cs_keys = get_key_struct();
ct->cs_key_even = dvbcsa_bs_key_alloc();
ct->cs_key_odd = dvbcsa_bs_key_alloc();
ct->cs_cwc = cwc;
ct->cs_service = t;
ct->cs_okchannel = -3;

View file

@ -468,8 +468,6 @@ main(int argc, char **argv)
htsp_init();
ffdecsa_init();
if(rawts_input != NULL)
rawts_init(rawts_input);