Commit ca48204a authored by npzacs's avatar npzacs
Browse files

Add basic CCI parsing

parent 72e4a984
......@@ -12,6 +12,9 @@ lib_LTLIBRARIES = libaacs.la
libaacs_la_SOURCES=\
src/libaacs/aacs.h \
src/libaacs/aacs.c \
src/libaacs/cci_data.h \
src/libaacs/cci.h \
src/libaacs/cci.c \
src/libaacs/content_cert.h \
src/libaacs/content_cert.c \
src/libaacs/crypto.h \
......
......@@ -26,6 +26,8 @@
#include "aacs-version.h"
#include "aacs.h"
#include "cci.h"
#include "cci_data.h"
#include "content_cert.h"
#include "crypto.h"
#include "mmc.h"
......@@ -772,6 +774,58 @@ static void _find_config_entry(AACS *aacs, title_entry_list *ce,
}
}
static size_t _read_cci_file(AACS *aacs, int cps_unit, void **data)
{
char *fname;
size_t size = 0;
fname = str_printf("AACS" DIR_SEP "CPSUnit%05d.cci", cps_unit);
if (fname) {
size = _read_file(aacs, fname, data);
X_FREE(fname);
if (size >= 2048) {
return size;
}
X_FREE(*data);
}
/* try backup copy */
fname = str_printf("AACS" DIR_SEP "DUPLICATE" DIR_SEP "CPSUnit%05d.cci", cps_unit);
if (fname) {
size = _read_file(aacs, fname, data);
X_FREE(fname);
if (size >= 2048) {
return size;
}
X_FREE(*data);
}
return 0;
}
static AACS_CCI *_read_cci(AACS *aacs, int cps_unit)
{
AACS_CCI *cci;
void *data;
size_t size;
size = _read_cci_file(aacs, cps_unit, &data);
if (!size) {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Failed to read CPS unit usage file %d\n", cps_unit);
return NULL;
}
cci = cci_parse(data, size);
X_FREE(data);
return cci;
}
static int _calc_uks(AACS *aacs, config_file *cf)
{
AACS_FILE_H *fp = NULL;
......@@ -1344,6 +1398,47 @@ uint32_t aacs_get_bus_encryption(AACS *aacs)
(aacs->bec * AACS_BUS_ENCRYPTION_CAPABLE);
}
static int _cps_unit(AACS *aacs, uint32_t title)
{
if (!aacs || !aacs->cps_units) {
BD_DEBUG(DBG_AACS|DBG_CRIT, "CPS units not read !\n");
return -1;
}
if (title == 0xffff) {
return aacs->cps_units[0];
} else if (title <= aacs->num_titles) {
return aacs->cps_units[title + 1];
}
BD_DEBUG(DBG_AACS|DBG_CRIT, "invalid title %u\n", title);
return -1;
}
struct aacs_basic_cci *aacs_get_basic_cci(AACS *aacs, uint32_t title)
{
AACS_BASIC_CCI *data = NULL;
int cps_unit;
cps_unit = _cps_unit(aacs, title);
if (cps_unit < 0) {
return NULL;
}
AACS_CCI *cci = _read_cci(aacs, cps_unit);
if (!cci) {
return NULL;
}
const AACS_BASIC_CCI *bcci = cci_get_basic_cci(cci);
if (bcci) {
data = malloc(sizeof(*data));
memcpy(data, bcci, sizeof(*data));
}
cci_free(&cci);
return data;
}
void aacs_select_title(AACS *aacs, uint32_t title)
{
......
......@@ -82,4 +82,10 @@ AACS_PUBLIC void aacs_free_rl(AACS_RL_ENTRY **rl);
AACS_PUBLIC uint32_t aacs_get_bus_encryption(AACS *);
/* Copy Control Information */
struct aacs_basic_cci;
AACS_PUBLIC struct aacs_basic_cci *aacs_get_basic_cci(AACS *, uint32_t title);
#endif /* AACS_H_ */
/*
* This file is part of libaacs
* Copyright (C) 2016 npzacs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "cci.h"
#include "cci_data.h"
#include "util/logging.h"
#include "util/macro.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define DBG_CCI DBG_AACS
/* CCI type */
enum {
cci_AACS_BASIC_CCI = 0x0101,
cci_AACS_ENHANCED_TITLE_USAGE = 0x0111,
};
typedef struct {
uint16_t type;
uint16_t version;
uint16_t data_length;
union {
AACS_BASIC_CCI basic_cci;
} u;
} AACS_CCI_ENTRY;
struct aacs_cci {
unsigned int num_entry;
AACS_CCI_ENTRY *entry;
};
static void _bitcpy(void *dst, const const void *src, size_t num_bits)
{
size_t bytes = num_bits >> 3;
size_t bits = num_bits & 3;
if (bytes) {
memcpy(dst, src, bytes);
}
if (bits) {
uint8_t mask = (((1 << (8 - bits))) - 1) ^ 0xff;
((uint8_t *)dst)[bytes] = ((const uint8_t *)src)[bytes] & mask;
}
}
static int cci_parse_entry(AACS_CCI_ENTRY *e, const uint8_t *data, size_t size)
{
memset(e, 0, sizeof(AACS_CCI_ENTRY));
if (size < 6) {
return -1;
}
e->type = MKINT_BE16(data);
e->version = MKINT_BE16(data + 2);
e->data_length = MKINT_BE16(data + 4);
if (size + 6 < e->data_length) {
BD_DEBUG(DBG_CCI, "CCI: not enough data (type 0x%04x)\n", e->type);
return -1;
}
switch (e->type) {
case cci_AACS_BASIC_CCI:
if (e->data_length == 0x84) {
BD_DEBUG(DBG_CCI, "CCI: AACS basic CCI found\n");
e->u.basic_cci.epn = (data[6] & 0x04) >> 2;
e->u.basic_cci.cci = data[6] & 0x03;
e->u.basic_cci.image_constraint = (data[7] & 0x10) >> 4;
e->u.basic_cci.digital_only = (data[7] & 0x40) >> 3;
e->u.basic_cci.apstb = data[7] & 0x07;
e->u.basic_cci.num_titles = MKINT_BE16(data + 8);
if (e->u.basic_cci.num_titles > 1024) {
BD_DEBUG(DBG_CCI, "CCI: title type map too large (%u)\n", e->u.basic_cci.num_titles);
return -1;
}
_bitcpy(e->u.basic_cci.title_type, data + 10, e->u.basic_cci.num_titles);
return 1;
}
break;
case cci_AACS_ENHANCED_TITLE_USAGE:
BD_DEBUG(DBG_CCI, "CCI: AACS enhanced title usage CCI found\n");
return 1;
default:
BD_DEBUG(DBG_CCI, "CCI: AACS CCI 0x%04x found\n", e->type);
break;
}
return 0;
}
AACS_CCI *cci_parse(const void *data, size_t size)
{
AACS_CCI *cci;
const uint8_t *p = data;
unsigned int ii;
if (size < 16) {
return NULL;
}
cci = calloc(1, sizeof(*cci));
if (!cci) {
return NULL;
}
cci->num_entry = MKINT_BE16(p);
p += 16;
size -= 16;
cci->entry = calloc(cci->num_entry, sizeof(*(cci->entry)));
if (!cci->entry) {
cci_free(&cci);
return NULL;
}
BD_DEBUG(DBG_CCI, "CCI: %d entries\n", cci->num_entry);
for (ii = 0; ii < cci->num_entry; ii++) {
AACS_CCI_ENTRY *e = &cci->entry[ii];
if (cci_parse_entry(e, p, size) < 0) {
BD_DEBUG(DBG_CCI, "CCI parsing failed\n");
cci_free(&cci);
return NULL;
}
p += 6 + e->data_length;
size -= 6 + e->data_length;
}
return cci;
}
void cci_free(AACS_CCI **pp)
{
if (pp && *pp) {
X_FREE((*pp)->entry);
X_FREE(*pp);
}
}
AACS_BASIC_CCI *cci_get_basic_cci(AACS_CCI *cci)
{
unsigned int ii;
for (ii = 0; ii < cci->num_entry; ii++) {
AACS_CCI_ENTRY *e = &cci->entry[ii];
if (e->type == cci_AACS_BASIC_CCI) {
return &e->u.basic_cci;
}
}
return NULL;
}
/*
* This file is part of libaacs
* Copyright (C) 2016 npzacs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef AACS_CCI_H_
#define AACS_CCI_H_
#include "util/attributes.h"
#include <stddef.h>
typedef struct aacs_cci AACS_CCI;
BD_PRIVATE AACS_CCI *cci_parse(const void *data, size_t len);
BD_PRIVATE void cci_free(AACS_CCI **);
BD_PRIVATE struct aacs_basic_cci *cci_get_basic_cci(AACS_CCI *cci);
#endif /* AACS_CCI_H_ */
/*
* This file is part of libaacs
* Copyright (C) 2016 npzacs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef AACS_CCI_DATA_H_
#define AACS_CCI_DATA_H_
#include <stdint.h>
/* Blu-ray Disc Pre-recorded Book, 3.9.4.2 Basic CCI for AACS */
typedef struct aacs_basic_cci {
uint8_t epn; /* Encryption Plus Non-assertion. Valid if cci == 0. */
uint8_t cci; /* Copy Control Information. 0 == copy freely. */
uint8_t image_constraint; /* High Definition Analog Output in High Definition Analog Form */
uint8_t digital_only; /* Output of decrypted content is allowed only for Digital Outputs */
uint8_t apstb; /* Analog copy protection information */
uint16_t num_titles;
/* title types (bit mask) */
uint8_t title_type[1024/8]; /* Title type bit mask. 0 == basic title. 1 == enhanced title. */
} AACS_BASIC_CCI;
#endif /* AACS_CCI_DATA_H_ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment