Commit fdfc19aa authored by npzacs's avatar npzacs

Calculate processing key using device keys

parent 21652191
......@@ -38,14 +38,17 @@
;
; Device Key entry
; ----------------
; | DK | DEVICE_KEY <HEXSTRING> | DEVICE_NODE <HEXSTRING>
; | DK | DEVICE_KEY <HEXSTRING> \
; | DEVICE_NODE <HEXSTRING> \
; | KEY_UV <HEXSTRING> \
; | KEY_U_MASK_SHIFT <HEXSTRING>
;
; The device key entry begins with the entry ID "| DK |". Within a device key
; entry are two hexadecimal strings. The first hexadecimal string is preceded by
; entry are four hexadecimal strings. The first hexadecimal string is preceded by
; the keyword "DEVICE_KEY" and is the hexadecimal string representing the device
; key. The second hexadecimal string is preceded by the keyword "DEVICE_NODE"
; and is the hexadecimal string representing the device node number. Each of
; two entries is delimited by a vertical bar '|'. Each device key entry must end
; four entries is delimited by a vertical bar '|'. Each device key entry must end
; with a newline.
;
; Note that each of these entries must end with at least one new line, as
......@@ -153,7 +156,9 @@
; foo's device key
| DK | DEVICE_KEY 0x00000000000000000000000000000000 \
| DEVICE_NODE 0x0
| DEVICE_NODE 0x0 \
| KEY_UV 0x00000000 \
| KEY_U_MASK 0x00
; bar's device key
| DK | DEVICE_KEY 0x00000000000000000000000000000000 \
......
......@@ -59,6 +59,8 @@ DIGIT ([0-9]+)
KEYWORD_DEVICE_KEY ([Dd][Ee][Vv][Ii][Cc][Ee]_[Kk][Ee][Yy])
KEYWORD_DEVICE_NODE ([Dd][Ee][Vv][Ii][Cc][Ee]_[Nn][Oo][Dd][Ee])
KEYWORD_KEY_UV ([Kk][Ee][Yy]_[Uu][Vv])
KEYWORD_KEY_U_MASK_SHIFT ([Kk][Ee][Yy]_[Uu]_[Mm][Aa][Ss][Kk]_[Ss][Hh][Ii][Ff][Tt])
KEYWORD_HOST_PRIV_KEY ([Hh][Oo][Ss][Tt]_[Pp][Rr][Ii][Vv]_[Kk][Ee][Yy][ \t]+)
KEYWORD_HOST_CERT ([Hh][Oo][Ss][Tt]_[Cc][Ee][Rr][Tt][ \t]+)
KEYWORD_HOST_NONCE ([Hh][Oo][Ss][Tt]_[Nn][Oo][Nn][Cc][Ee][ \t]+)
......@@ -112,6 +114,8 @@ BAD_ENTRY ([^\n])
{KEYWORD_DEVICE_KEY} { return KEYWORD_DEVICE_KEY; }
{KEYWORD_DEVICE_NODE} { return KEYWORD_DEVICE_NODE; }
{KEYWORD_KEY_UV} { return KEYWORD_KEY_UV; }
{KEYWORD_KEY_U_MASK_SHIFT} { return KEYWORD_KEY_U_MASK_SHIFT; }
{KEYWORD_HOST_PRIV_KEY} { return KEYWORD_HOST_PRIV_KEY; }
{KEYWORD_HOST_CERT} { return KEYWORD_HOST_CERT; }
{KEYWORD_HOST_NONCE} { return KEYWORD_HOST_NONCE; }
......
......@@ -69,7 +69,7 @@ static dk_list *new_dk_list(void);
static pk_list *new_pk_list(void);
static cert_list *new_cert_list(void);
static void add_dk_entry(config_file *cf, char *key, char *node);
static void add_dk_entry(config_file *cf, char *key, char *node, char *uv, char *u_mask_shift);
static void add_pk_entry(config_file *cf, char *key);
static void add_cert_entry(config_file *cf, char *host_priv_key, char *host_cert);
......@@ -114,6 +114,8 @@ extern int libaacs_yyget_lineno (void *scanner);
%token KEYWORD_DEVICE_KEY
%token KEYWORD_DEVICE_NODE
%token KEYWORD_KEY_UV
%token KEYWORD_KEY_U_MASK_SHIFT
%token KEYWORD_HOST_PRIV_KEY
%token KEYWORD_HOST_CERT
%token KEYWORD_HOST_NONCE
......@@ -140,7 +142,7 @@ extern int libaacs_yyget_lineno (void *scanner);
%type <string> discid disc_title
%type <string> host_priv_key host_cert host_nonce host_key_point hexstring_list
%type <string> device_key device_node
%type <string> device_key device_node key_uv key_u_mask_shift
%%
config_file
: config_entry_list newline_list
......@@ -168,13 +170,21 @@ config_entry
;
dk_entry
: newline_list ENTRY_ID_DK device_key PUNCT_VERTICAL_BAR device_node NEWLINE
: newline_list ENTRY_ID_DK device_key PUNCT_VERTICAL_BAR device_node PUNCT_VERTICAL_BAR key_uv PUNCT_VERTICAL_BAR key_u_mask_shift NEWLINE
{
add_dk_entry(cf, $3, $5);
add_dk_entry(cf, $3, $5, $7, $9);
}
| newline_list ENTRY_ID_DK device_key PUNCT_VERTICAL_BAR device_node NEWLINE
{
add_dk_entry(cf, $3, $5, NULL, NULL);
}
| ENTRY_ID_DK device_key PUNCT_VERTICAL_BAR device_node PUNCT_VERTICAL_BAR key_uv PUNCT_VERTICAL_BAR key_u_mask_shift NEWLINE
{
add_dk_entry(cf, $2, $4, $6, $8);
}
| ENTRY_ID_DK device_key PUNCT_VERTICAL_BAR device_node NEWLINE
{
add_dk_entry(cf, $2, $4);
add_dk_entry(cf, $2, $4, NULL, NULL);
}
;
......@@ -188,6 +198,16 @@ device_node
{ $$ = $2; }
;
key_uv
: KEYWORD_KEY_UV hexstring_list
{ $$ = $2; }
;
key_u_mask_shift
: KEYWORD_KEY_U_MASK_SHIFT hexstring_list
{ $$ = $2; }
;
pk_entry
: newline_list ENTRY_ID_PK hexstring_list NEWLINE
{
......@@ -537,7 +557,7 @@ static dk_list *new_dk_list(void)
}
/* Function to add dk to config file */
static void add_dk_entry(config_file *cf, char *key, char *node)
static void add_dk_entry(config_file *cf, char *key, char *node, char *uv, char *u_mask_shift)
{
if (strlen(key) != 32) {
fprintf(stderr, "ignoring bad DK entry %s\n", key);
......@@ -558,6 +578,15 @@ static void add_dk_entry(config_file *cf, char *key, char *node)
X_FREE(key);
entry->node = strtoul(node, NULL, 16);
X_FREE(node);
if (uv) {
entry->uv = strtoul(uv, NULL, 16);
X_FREE(uv);
}
if (u_mask_shift) {
entry->u_mask_shift = strtoul(u_mask_shift, NULL, 16);
X_FREE(u_mask_shift);
}
}
/* Function to return new pk_list object */
......
......@@ -56,6 +56,10 @@ struct dk_entry
uint8_t key[16];
unsigned long node;
dk_list *next;
/* optional, can be calculated */
uint32_t uv;
uint8_t u_mask_shift;
};
/* pk entry */
......
......@@ -156,11 +156,195 @@ static void _update_drl(MKB *mkb)
}
}
static int _calc_mk(AACS *aacs, uint8_t *mk, pk_list *pkl)
static uint32_t _calc_v_mask(uint32_t uv)
{
uint32_t v_mask = 0xffffffff;
while (!(uv & ~v_mask)) {
v_mask <<= 1;
}
return v_mask;
}
static void _calc_pk(const uint8_t *dk, uint8_t *pk, uint32_t uv, uint32_t v_mask, uint32_t dev_key_v_mask)
{
unsigned char left_child[16], right_child[16];
crypto_aesg3(dk, left_child, right_child, pk);
while (dev_key_v_mask != v_mask) {
int i;
for (i = 31; i >= 0; i--) {
if (!(dev_key_v_mask & (1ul << i))) {
break;
}
}
uint8_t curr_key[16];
if (!(uv & (1ul << i))) {
memcpy(curr_key, left_child, 16);
} else {
memcpy(curr_key, right_child, 16);
}
crypto_aesg3(curr_key, left_child, right_child, pk);
dev_key_v_mask = ((int) dev_key_v_mask) >> 1;
}
char str[40];
DEBUG(DBG_AACS, "Processing key: %s\n", print_hex(str, pk, 16));
}
static dk_list *_find_dk(dk_list *dkl, uint32_t *p_dev_key_v_mask, uint32_t uv, uint32_t u_mask)
{
uint32_t device_number = dkl->node;
uint32_t dev_key_uv, dev_key_u_mask, dev_key_v_mask;
unsigned key_idx = 0;
for (; dkl; dkl = dkl->next) {
if (device_number != dkl->node) {
/* wrong device */
continue;
}
key_idx++;
dev_key_uv = dkl->uv;
dev_key_u_mask = 0xffffffff << dkl->u_mask_shift;
dev_key_v_mask = _calc_v_mask(dev_key_uv);
if ((u_mask == dev_key_u_mask) &&
((uv & dev_key_v_mask) == (dev_key_uv & dev_key_v_mask))) {
break;
}
}
if (!dkl) {
DEBUG(DBG_AACS | DBG_CRIT, "could not find applying device key (device 0x%x)\n", device_number);
} else {
char str[128];
DEBUG(DBG_AACS, "Applying device key is #%d %s\n", key_idx, print_hex(str, dkl->key, 16));
DEBUG(DBG_AACS, " UV: 0x%08x U mask: 0x%08x V mask: 0x%08x\n", dev_key_uv, dev_key_u_mask, dev_key_v_mask);
*p_dev_key_v_mask = dev_key_v_mask;
}
return dkl;
}
static int _calc_pk_mk(MKB *mkb, dk_list *dkl, uint8_t *mk)
{
/* calculate processing key and media key using device keys */
const uint8_t *uvs, *cvalues;
unsigned num_uvs;
size_t len;
char str[128];
/* get mkb data */
uvs = mkb_subdiff_records(mkb, &len);
cvalues = mkb_cvalues(mkb, &len);
num_uvs = len / 5;
if (num_uvs < 1) {
return AACS_ERROR_CORRUPTED_DISC;
}
/* loop over all known devices */
dk_list *dk_num;
uint32_t device_number = (uint32_t)-1;
for (dk_num = dkl; dk_num; dk_num = dk_num->next) {
/* find next device */
if (device_number == dk_num->node) {
dk_num = dk_num->next;
continue;
}
device_number = dkl->node;
/* find applying subset difference */
unsigned uvs_idx;
uint32_t u_mask, v_mask, uv;
for (uvs_idx = 0; uvs_idx < num_uvs; uvs_idx++) {
const uint8_t *p_uv = uvs + 1 + 5 * uvs_idx;
uint8_t u_mask_shift = p_uv[-1];
uv = MKINT_BE32(p_uv);
if (!uv) {
continue;
}
if (u_mask_shift & 0xc0) {
DEBUG(DBG_AACS | DBG_CRIT, "device 0x%x is revoked\n", device_number);
uvs_idx = num_uvs;
} else {
u_mask = 0xffffffff << u_mask_shift;
v_mask = _calc_v_mask(uv);
if (((device_number & u_mask) == (uv & u_mask)) && ((device_number & v_mask) != (uv & v_mask))) {
break;
}
}
}
if (uvs_idx >= num_uvs) {
DEBUG(DBG_AACS | DBG_CRIT, "could not find applying subset-difference for device 0x%x\n", device_number);
/* try next device */
continue;
}
DEBUG(DBG_AACS, "Applying subset-difference for device 0x%x is #%d:\n", device_number, uvs_idx);
DEBUG(DBG_AACS," UV: 0x%08x U mask: 0x%08x V mask: 0x%08x\n", uv, u_mask, v_mask);
/* find applying device key */
uint32_t dev_key_v_mask = 0;
dk_list *dk;
dk = _find_dk(dk_num, &dev_key_v_mask, uv, u_mask);
if (!dk) {
/* try next device */
continue;
}
/* calculate processing key */
uint8_t pk[16];
_calc_pk(dk->key, pk, uv, v_mask, dev_key_v_mask);
/* calculate and verify media key */
if ( _validate_pk(pk,
cvalues + uvs_idx * 16,
uvs + 1 + uvs_idx * 5,
mkb_mk_dv(mkb),
mk)
== AACS_SUCCESS) {
DEBUG(DBG_AACS, "Media key: %s\n", print_hex(str, mk, 16));
return AACS_SUCCESS;
}
DEBUG(DBG_AACS | DBG_CRIT, "Processing key %s is invalid!\n", print_hex(str, pk, 16));
/* try next device */
}
return AACS_ERROR_NO_DK;
}
static int _calc_mk(AACS *aacs, uint8_t *mk, pk_list *pkl, dk_list *dkl)
{
int a, num_uvs = 0;
size_t len;
uint8_t *buf = NULL;
MKB *mkb = NULL;
const uint8_t *rec, *uvs;
......@@ -172,9 +356,17 @@ static int _calc_mk(AACS *aacs, uint8_t *mk, pk_list *pkl)
DEBUG(DBG_AACS, "Calculate media key...\n");
if ((mkb = mkb_open(aacs->path))) {
DEBUG(DBG_AACS, "Get UVS...\n");
_update_drl(mkb);
aacs->mkb_version = mkb_version(mkb);
_update_drl(mkb);
/* try device keys first */
if (dkl && _calc_pk_mk(mkb, dkl, mk) == AACS_SUCCESS) {
mkb_close(mkb);
return AACS_SUCCESS;
}
DEBUG(DBG_AACS, "Get UVS...\n");
uvs = mkb_subdiff_records(mkb, &len);
rec = uvs;
while (rec < uvs + len) {
......@@ -194,7 +386,6 @@ static int _calc_mk(AACS *aacs, uint8_t *mk, pk_list *pkl)
if (AACS_SUCCESS == _validate_pk(pkl->key, rec + a * 16, uvs + 1 + a * 5,
mkb_mk_dv(mkb), mk)) {
mkb_close(mkb);
X_FREE(buf);
char str[40];
DEBUG(DBG_AACS, "Media key: %s\n", print_hex(str, mk, 16));
......@@ -204,7 +395,6 @@ static int _calc_mk(AACS *aacs, uint8_t *mk, pk_list *pkl)
}
mkb_close(mkb);
X_FREE(buf);
DEBUG(DBG_AACS | DBG_CRIT, "Error calculating media key. Missing right processing key ?\n");
return AACS_ERROR_NO_PK;
......@@ -387,7 +577,7 @@ static int _calc_vuk(AACS *aacs, uint8_t *mk, uint8_t *vuk, config_file *cf)
}
/* make sure we have media key */
error_code = _calc_mk(aacs, mk, cf->pkl);
error_code = _calc_mk(aacs, mk, cf->pkl, cf->dkl);
if (error_code != AACS_SUCCESS) {
return error_code;
}
......
......@@ -35,6 +35,7 @@
#define AACS_ERROR_CERT_REVOKED -5 /* certificate has been revoked */
#define AACS_ERROR_MMC_OPEN -6 /* MMC open failed (no MMC drive ?) */
#define AACS_ERROR_MMC_FAILURE -7 /* MMC failed */
#define AACS_ERROR_NO_DK -8 /* no matching device key */
typedef struct aacs AACS;
......
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