aacs.c 25.2 KB
Newer Older
1 2
/*
 * This file is part of libaacs
3
 * Copyright (C) 2009-2010  Obliter0n
npzacs's avatar
npzacs committed
4
 * Copyright (C) 2009-2010  npzacs
5
 *
gates's avatar
gates committed
6 7 8 9
 * 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.
10
 *
gates's avatar
gates committed
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
gates's avatar
gates committed
13 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
15
 *
gates's avatar
gates committed
16 17 18
 * 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/>.
19 20
 */

npzacs's avatar
npzacs committed
21 22 23 24
#if HAVE_CONFIG_H
#include "config.h"
#endif

npzacs's avatar
npzacs committed
25 26
#include <util/attributes.h>

npzacs's avatar
npzacs committed
27
#include "aacs-version.h"
cRTrn13's avatar
cRTrn13 committed
28
#include "aacs.h"
29
#include "crypto.h"
cRTrn13's avatar
cRTrn13 committed
30
#include "mmc.h"
31
#include "mkb.h"
gates's avatar
gates committed
32
#include "file/file.h"
gates's avatar
gates committed
33
#include "file/keydbcfg.h"
34 35
#include "util/macro.h"
#include "util/logging.h"
36
#include "util/strutl.h"
cRTrn13's avatar
cRTrn13 committed
37

38
#include <inttypes.h>
39
#include <string.h>
40
#include <stdio.h>
npzacs's avatar
npzacs committed
41 42 43
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
44
#include <gcrypt.h>
45

npzacs's avatar
npzacs committed
46

npzacs's avatar
npzacs committed
47
struct aacs {
npzacs's avatar
npzacs committed
48 49 50 51 52
    /* current disc */
    char     *path;
    int       mkb_version;
    uint8_t   disc_id[20];

53 54
    /* VID is cached for BD-J */
    uint8_t   vid[16];
55 56
    /* PMSN is cached for BD-J */
    uint8_t   pmsn[16];
npzacs's avatar
npzacs committed
57 58 59 60

    /* unit key for each CPS unit */
    uint32_t  num_uks;
    uint8_t  *uks;
npzacs's avatar
npzacs committed
61

npzacs's avatar
npzacs committed
62 63 64 65 66 67
    /* CPS unit of currently selected title */
    uint16_t  current_cps_unit;

    /* title -> CPS unit mappings */
    uint32_t  num_titles;
    uint16_t *cps_units;  /* [0] = first play ; [1] = top menu ; [2] = title 1 ... */
npzacs's avatar
npzacs committed
68 69
};

70 71 72
static const uint8_t empty_key[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
                                   "\x00\x00\x00\x00\x00\x00\x00\x00";

73 74
static int _validate_pk(const uint8_t *pk,
                        const uint8_t *cvalue, const uint8_t *uv, const uint8_t *vd,
npzacs's avatar
npzacs committed
75
                        uint8_t *mk)
cRTrn13's avatar
cRTrn13 committed
76
{
77
    gcry_cipher_hd_t gcry_h;
npzacs's avatar
npzacs committed
78
    int a;
cRTrn13's avatar
cRTrn13 committed
79
    uint8_t dec_vd[16];
80
    char str[40];
cRTrn13's avatar
cRTrn13 committed
81

82
    DEBUG(DBG_AACS, "Validate processing key %s...\n", print_hex(str, pk, 16));
cRTrn13's avatar
cRTrn13 committed
83
    DEBUG(DBG_AACS, " Using:\n");
84 85 86
    DEBUG(DBG_AACS, "   UV: %s\n", print_hex(str, uv, 4));
    DEBUG(DBG_AACS, "   cvalue: %s\n", print_hex(str, cvalue, 16));
    DEBUG(DBG_AACS, "   Verification data: %s\n", print_hex(str, vd, 16));
87

88 89 90
    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
    gcry_cipher_setkey(gcry_h, pk, 16);
    gcry_cipher_decrypt(gcry_h, mk, 16, cvalue, 16);
91

cRTrn13's avatar
cRTrn13 committed
92 93 94 95
    for (a = 0; a < 4; a++) {
        mk[a + 12] ^= uv[a];
    }

96 97 98
    gcry_cipher_setkey(gcry_h, mk, 16);
    gcry_cipher_decrypt (gcry_h, dec_vd, 16, vd, 16);
    gcry_cipher_close(gcry_h);
99

cRTrn13's avatar
cRTrn13 committed
100
    if (!memcmp(dec_vd, "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8)) {
npzacs's avatar
npzacs committed
101
        DEBUG(DBG_AACS, "Processing key %s is valid!\n", print_hex(str, pk, 16));
npzacs's avatar
npzacs committed
102
        return AACS_SUCCESS;
cRTrn13's avatar
cRTrn13 committed
103 104
    }

npzacs's avatar
npzacs committed
105
    return AACS_ERROR_NO_PK;
cRTrn13's avatar
cRTrn13 committed
106
}
107

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
static int _rl_verify_signature(const uint8_t *rl, size_t size)
{
    int    entries = MKINT_BE32(rl + 12 + 8);
    size_t len     = 12 + 12 + 8 * entries; /* type_and_version_rec=12, rl_header=12, rl=entries*8 */

    if (len + 40 > size) {
        DEBUG(DBG_AACS, "revocation list size mismatch\n");
        return 0;
    }

    return crypto_aacs_verify_aacsla(rl + len, rl, len);
}

static void _update_drl(MKB *mkb)
{
    uint32_t version = mkb_version(mkb);
    uint32_t cache_version;

    if (!cache_get("drl", &cache_version, NULL, NULL) || cache_version < version) {
        size_t drl_len;
        const uint8_t *drl_rec = mkb_drive_revokation_entries(mkb, &drl_len);
        const uint8_t *v_rec   = mkb_type_and_version_record(mkb);

        if (drl_rec && v_rec) {
            drl_rec -= 4;
            drl_len += 4;

            uint8_t *data = malloc(12 + drl_len);
            memcpy(data,      v_rec,   12);
            memcpy(data + 12, drl_rec, drl_len);
            if (!_rl_verify_signature(data, drl_len + 12)) {
                DEBUG(DBG_AACS | DBG_CRIT, "invalid drive revocation list signature, not using it\n");
            } else {
                cache_save("drl", version, data, drl_len + 12);
            }
            X_FREE(data);
        }
    }
}

148
static int _calc_mk(AACS *aacs, uint8_t *mk, pk_list *pkl)
cRTrn13's avatar
keyfile  
cRTrn13 committed
149 150 151
{
    int a, num_uvs = 0;
    size_t len;
152
    uint8_t *buf = NULL;
cRTrn13's avatar
keyfile  
cRTrn13 committed
153
    MKB *mkb = NULL;
154
    const uint8_t *rec, *uvs;
cRTrn13's avatar
keyfile  
cRTrn13 committed
155

156
    /* Skip if retrieved from config file */
157 158 159
    if (memcmp(mk, empty_key, 16)) {
        return AACS_SUCCESS;
    }
160

cRTrn13's avatar
cRTrn13 committed
161 162
    DEBUG(DBG_AACS, "Calculate media key...\n");

npzacs's avatar
npzacs committed
163
    if ((mkb = mkb_open(aacs->path))) {
164
        DEBUG(DBG_AACS, "Get UVS...\n");
165
        _update_drl(mkb);
npzacs's avatar
npzacs committed
166
        aacs->mkb_version = mkb_version(mkb);
167 168 169 170 171 172 173 174
        uvs = mkb_subdiff_records(mkb, &len);
        rec = uvs;
        while (rec < uvs + len) {
            if (rec[0] & 0xc0)
                break;
            rec += 5;
            num_uvs++;
        }
cRTrn13's avatar
keyfile  
cRTrn13 committed
175

176 177
        DEBUG(DBG_AACS, "Get cvalues...\n");
        rec = mkb_cvalues(mkb, &len);
178 179

        for (; pkl && pkl->key; pkl = pkl->next) {
180
                uint8_t pk[16];
181
                hexstring_to_hex_array(pk, sizeof(pk), pkl->key);
182 183 184
                DEBUG(DBG_AACS, "Trying processing key...\n");

                for (a = 0; a < num_uvs; a++) {
185
                    if (AACS_SUCCESS == _validate_pk(pk, rec + a * 16, uvs + 1 + a * 5,
186
                      mkb_mk_dv(mkb), mk)) {
187 188
                        mkb_close(mkb);
                        X_FREE(buf);
189

190
                        char str[40];
191
                        DEBUG(DBG_AACS, "Media key: %s\n", print_hex(str, mk, 16));
npzacs's avatar
npzacs committed
192
                        return AACS_SUCCESS;
193 194
                    }
                }
cRTrn13's avatar
keyfile  
cRTrn13 committed
195 196
            }

197 198
        mkb_close(mkb);
        X_FREE(buf);
cRTrn13's avatar
keyfile  
cRTrn13 committed
199

npzacs's avatar
npzacs committed
200
        DEBUG(DBG_AACS | DBG_CRIT, "Error calculating media key. Missing right processing key ?\n");
npzacs's avatar
npzacs committed
201
        return AACS_ERROR_NO_PK;
npzacs's avatar
npzacs committed
202
    }
npzacs's avatar
npzacs committed
203

npzacs's avatar
npzacs committed
204
    DEBUG(DBG_AACS | DBG_CRIT, "Error opening %s/AACS/MKB_RO.inf\n", aacs->path);
npzacs's avatar
npzacs committed
205
    return AACS_ERROR_CORRUPTED_DISC;
cRTrn13's avatar
keyfile  
cRTrn13 committed
206
}
207

208 209 210 211
static MKB *_get_hrl_mkb(MMC *mmc)
{
    MKB     *mkb = NULL;
    uint8_t *data;
npzacs's avatar
npzacs committed
212
    int      mkb_size;
213

npzacs's avatar
npzacs committed
214
    data = mmc_read_mkb(mmc, 0, &mkb_size);
215 216

    /* check acquired hrl signature */
npzacs's avatar
npzacs committed
217 218 219
    if (data && mkb_size > 0) {
        if (_rl_verify_signature(data, mkb_size)) {
            mkb = mkb_init(data, mkb_size);
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
            DEBUG(DBG_AACS, "Partial hrl mkb read. Version: %d\n", mkb_version(mkb));
        } else {
            DEBUG(DBG_AACS | DBG_CRIT, "invalid host revocation list signature, not using it\n");
            X_FREE(data);
        }
    }

    if (mkb) {
        /* use latest version, keep cache up-to-date */
        uint32_t size;
        size = mkb_data_size(mkb);
        data = cache_get_or_update("hrl", mkb_data(mkb), &size, mkb_version(mkb));

        if (!_rl_verify_signature(data, size)) {
            DEBUG(DBG_AACS | DBG_CRIT, "invalid cached revocation list signature, replacing it\n");
            cache_save("hrl", mkb_version(mkb), mkb_data(mkb), mkb_data_size(mkb));
            X_FREE(data);
        } else {
            /* use cached version */
            mkb_close(mkb);
            mkb = mkb_init(data, size);
        }

    } else {
        /* use cached version */
        uint32_t size;
        data = cache_get_or_update("hrl", NULL, &size, 0);
        if (data && size > 0) {
            if (!_rl_verify_signature(data, size)) {
                mkb = mkb_init(data, size);
            } else {
                DEBUG(DBG_AACS | DBG_CRIT, "invalid cached revocation list signature, deleting cache\n");
                cache_remove("hrl");
            }
        }
    }


    if (mkb) {
        DEBUG(DBG_AACS, "Using hrl version %d\n", mkb_version(mkb));
    }

    return mkb;
}

265
static int _read_vid(AACS *aacs, cert_list *hcl, int force_mmc)
cRTrn13's avatar
openssl  
cRTrn13 committed
266
{
267
    /* Use VID given in config file if available */
268
    if (!force_mmc && memcmp(aacs->vid, empty_key, 16)) {
npzacs's avatar
npzacs committed
269
        return AACS_SUCCESS;
270 271
    }

cRTrn13's avatar
cRTrn13 committed
272
    MMC* mmc = NULL;
npzacs's avatar
npzacs committed
273
    if (!(mmc = mmc_open(aacs->path))) {
npzacs's avatar
npzacs committed
274
        return AACS_ERROR_MMC_OPEN;
275 276
    }

npzacs's avatar
npzacs committed
277 278
    int error_code = AACS_ERROR_NO_CERT;

279 280
    MKB *hrl_mkb = _get_hrl_mkb(mmc);

281
    for (;hcl && hcl->host_priv_key && hcl->host_cert; hcl = hcl->next) {
282 283 284

        char tmp_str[2*92+1];
        uint8_t priv_key[20], cert[92];
285 286
        hexstring_to_hex_array(priv_key, sizeof(priv_key), hcl->host_priv_key);
        hexstring_to_hex_array(cert,     sizeof(cert),     hcl->host_cert);
287 288

        if (!crypto_aacs_verify_host_cert(cert)) {
npzacs's avatar
npzacs committed
289 290 291 292
            DEBUG(DBG_AACS, "Not using invalid host certificate %s.\n",
                  print_hex(tmp_str, cert, 92));
            continue;
        }
293

294 295 296 297 298 299 300
        if (mkb_host_cert_is_revoked(hrl_mkb, cert + 4)) {
            DEBUG(DBG_AACS | DBG_CRIT, "Host certificate %s has been revoked.\n",
                  print_hex(tmp_str, cert + 4, 6));
            error_code = AACS_ERROR_CERT_REVOKED;
            //continue;
        }

301 302 303
        DEBUG(DBG_AACS, "Trying host certificate (id 0x%s)...\n",
              print_hex(tmp_str, cert + 4, 6));

304
        int mmc_result = mmc_read_vid(mmc, priv_key, cert, aacs->vid, aacs->pmsn);
npzacs's avatar
npzacs committed
305 306
        switch (mmc_result) {
            case MMC_SUCCESS:
307
                mkb_close(hrl_mkb);
npzacs's avatar
npzacs committed
308
                mmc_close(mmc);
npzacs's avatar
npzacs committed
309 310
                /* cache vid */
                keycache_save("vid", aacs->disc_id, aacs->vid, 16);
npzacs's avatar
npzacs committed
311 312 313 314 315 316 317 318
                return AACS_SUCCESS;
            case MMC_ERROR_CERT_REVOKED:
                error_code = AACS_ERROR_CERT_REVOKED;
                break;
            case MMC_ERROR:
            default:
                error_code = AACS_ERROR_MMC_FAILURE;
                break;
319 320 321
        }
    }

322
    mkb_close(hrl_mkb);
323 324 325
    mmc_close(mmc);

    DEBUG(DBG_AACS, "Error reading VID!\n");
npzacs's avatar
npzacs committed
326
    return error_code;
327
}
cRTrn13's avatar
openssl  
cRTrn13 committed
328

329
static int _calc_vuk(AACS *aacs, uint8_t *mk, uint8_t *vuk,
npzacs's avatar
npzacs committed
330
                     pk_list *pkl, cert_list *host_cert_list)
331
{
npzacs's avatar
npzacs committed
332 333
    int error_code;

334
    /* Skip if retrieved from config file */
335
    if (memcmp(vuk, empty_key, 16)) {
npzacs's avatar
npzacs committed
336 337 338
        DEBUG(DBG_AACS, "Using VUK from config file\n");
        return AACS_SUCCESS;
    }
339

npzacs's avatar
npzacs committed
340
    /* get cached vuk */
341
    if (keycache_find("vuk", aacs->disc_id, vuk, 16)) {
npzacs's avatar
npzacs committed
342
        DEBUG(DBG_AACS, "Using cached VUK\n");
npzacs's avatar
npzacs committed
343
        return AACS_SUCCESS;
npzacs's avatar
npzacs committed
344 345
    }

346
    /* make sure we have media key */
npzacs's avatar
npzacs committed
347
    error_code = _calc_mk(aacs, mk, pkl);
npzacs's avatar
npzacs committed
348 349
    if (error_code != AACS_SUCCESS) {
        return error_code;
350 351
    }

npzacs's avatar
npzacs committed
352
    /* acquire VID */
353
    error_code = _read_vid(aacs, host_cert_list, 0);
npzacs's avatar
npzacs committed
354 355 356
    if (error_code != AACS_SUCCESS) {
        return error_code;
    }
357

npzacs's avatar
npzacs committed
358 359
    int a;
    gcry_cipher_hd_t gcry_h;
360

npzacs's avatar
npzacs committed
361
    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
362 363
    gcry_cipher_setkey(gcry_h, mk, 16);
    gcry_cipher_decrypt(gcry_h, vuk, 16, aacs->vid, 16);
npzacs's avatar
npzacs committed
364
    gcry_cipher_close(gcry_h);
365

npzacs's avatar
npzacs committed
366
    for (a = 0; a < 16; a++) {
367
        vuk[a] ^= aacs->vid[a];
npzacs's avatar
npzacs committed
368
    }
369

npzacs's avatar
npzacs committed
370
    char str[40];
371
    DEBUG(DBG_AACS, "Volume unique key: %s\n", print_hex(str, vuk, 16));
372

npzacs's avatar
npzacs committed
373
    /* cache vuk */
374
    keycache_save("vuk", aacs->disc_id, vuk, 16);
npzacs's avatar
npzacs committed
375

npzacs's avatar
npzacs committed
376
    return AACS_SUCCESS;
cRTrn13's avatar
openssl  
cRTrn13 committed
377 378
}

379 380
static uint16_t _read_u16(AACS_FILE_H *fp)
{
npzacs's avatar
npzacs committed
381
  uint8_t data[2] = {0, 0};
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427

  file_read(fp, data, sizeof(uint16_t));

  return MKINT_BE16(data);
}

static void _read_uks_map(AACS *aacs, AACS_FILE_H *fp)
{
    uint16_t first_play, top_menu;
    unsigned i;

    DEBUG(DBG_AACS, "Assigning CPS units to titles ...\n");

    X_FREE(aacs->cps_units);
    aacs->current_cps_unit = 0;

    file_seek(fp, 16 + 4, SEEK_SET);

    first_play = _read_u16(fp);
    top_menu   = _read_u16(fp);

    DEBUG(DBG_AACS, "Title FP : CPS unit %d\n", first_play);
    DEBUG(DBG_AACS, "Title TM : CPS unit %d\n", top_menu);

    aacs->num_titles   = _read_u16(fp);
    aacs->cps_units    = calloc(sizeof(uint16_t), aacs->num_titles + 2);
    aacs->cps_units[0] = first_play;
    aacs->cps_units[1] = top_menu;

    for (i = 2; i < aacs->num_titles + 2; i++) {
        _read_u16(fp); /* reserved */
        aacs->cps_units[i] = _read_u16(fp);
        DEBUG(DBG_AACS, "Title %02d : CPS unit %d\n", i - 1, aacs->cps_units[i]);
    }

    /* validate */
    for (i = 0; i < aacs->num_titles + 2; i++) {
        if (aacs->cps_units[i])
            aacs->cps_units[i]--; /* number [1...N] --> index [0...N-1] */
        if (aacs->cps_units[i] >= aacs->num_uks) {
            DEBUG(DBG_AACS, " *** Invalid CPS unit for title %d: %d !\n", (int) i - 1, aacs->cps_units[i]);
            aacs->cps_units[i] = 0;
        }
    }
}

npzacs's avatar
npzacs committed
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
static AACS_FILE_H *_open_unit_key_file(const char *path)
{
    AACS_FILE_H *fp;
    char        *f_name;

    f_name = str_printf("%s/AACS/Unit_Key_RO.inf", path);
    fp = file_open(f_name, "rb");

    if (!fp) {
        DEBUG(DBG_AACS | DBG_CRIT, "Error opening unit key file %s\n", f_name);
    }

    X_FREE(f_name);
    return fp;
}

npzacs's avatar
npzacs committed
444
/* Function that collects keys from keydb config entry */
445 446
static void _find_config_entry(AACS *aacs, title_entry_list *ce,
                               uint8_t *mk, uint8_t *vuk)
npzacs's avatar
npzacs committed
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
{
    uint8_t discid[20];
    char str[48];

    aacs->uks = NULL;
    aacs->num_uks = 0;

        while (ce && ce->entry.discid) {
            memset(discid, 0, sizeof(discid));
            hexstring_to_hex_array(discid, sizeof(discid),
                                   ce->entry.discid);
            if (!memcmp(aacs->disc_id, discid, 20)) {
                DEBUG(DBG_AACS, "Found config entry for discid %s\n",
                      ce->entry.discid);
                break;
            }

            ce = ce->next;
        }
        if (!ce) {
            return;
        }

        if (ce->entry.mek) {
471
            hexstring_to_hex_array(mk, 16, ce->entry.mek);
npzacs's avatar
npzacs committed
472 473

            DEBUG(DBG_AACS, "Found media key for %s: %s\n",
474
                  ce->entry.discid, print_hex(str, mk, 16));
npzacs's avatar
npzacs committed
475 476 477 478 479 480 481 482 483 484 485
        }

        if (ce->entry.vid) {
            hexstring_to_hex_array(aacs->vid, sizeof(aacs->vid),
                                    ce->entry.vid);

            DEBUG(DBG_AACS, "Found volume id for %s: %s\n",
                  ce->entry.discid, print_hex(str, aacs->vid, 16));
        }

        if (ce->entry.vuk) {
486
            hexstring_to_hex_array(vuk, 16, ce->entry.vuk);
npzacs's avatar
npzacs committed
487 488

            DEBUG(DBG_AACS, "Found volume unique key for %s: %s\n",
489
                  ce->entry.discid, print_hex(str, vuk, 16));
npzacs's avatar
npzacs committed
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
        }

        if (ce->entry.uk) {
            DEBUG(DBG_AACS, "Acquire CPS unit keys from keydb config file...\n");

            digit_key_pair_list *ukcursor = ce->entry.uk;
            while (ukcursor && ukcursor->key_pair.key) {
                aacs->num_uks++;

                aacs->uks = (uint8_t*)realloc(aacs->uks, 16 * aacs->num_uks);
                hexstring_to_hex_array(aacs->uks + (16 * (aacs->num_uks - 1)), 16,
                                      ukcursor->key_pair.key);

                DEBUG(DBG_AACS, "Unit key %d from keydb entry: %s\n",
                      aacs->num_uks,
                      print_hex(str, aacs->uks + (16 * (aacs->num_uks - 1)), 16));

                ukcursor = ukcursor->next;
            }
        }
}

512
static int _calc_uks(AACS *aacs, const char *configfile_path)
cRTrn13's avatar
openssl  
cRTrn13 committed
513
{
514
    AACS_FILE_H *fp = NULL;
515
    uint8_t  buf[16];
516
    uint64_t f_pos;
517
    unsigned int i;
npzacs's avatar
npzacs committed
518
    int error_code;
cRTrn13's avatar
openssl  
cRTrn13 committed
519

520 521 522 523 524 525 526 527 528 529 530
    config_file *cf = NULL;
    uint8_t mk[16] = {0}, vuk[16] = {0};

    cf = keydbcfg_config_load(configfile_path);
    if (!cf) {
        return AACS_ERROR_NO_CONFIG;
    }

    DEBUG(DBG_AACS, "Searching for keydb config entry...\n");
    _find_config_entry(aacs, cf->list, mk, vuk);

531
    /* Skip if retrieved from config file */
532 533
    if (aacs->uks) {
        keydbcfg_config_file_close(cf);
npzacs's avatar
npzacs committed
534
        return AACS_SUCCESS;
535
    }
536

537
    /* Make sure we have VUK */
538 539
    error_code = _calc_vuk(aacs, mk, vuk, cf->pkl, cf->host_cert_list);
    keydbcfg_config_file_close(cf);
npzacs's avatar
npzacs committed
540 541
    if (error_code != AACS_SUCCESS) {
        return error_code;
542
    }
543

544 545
    DEBUG(DBG_AACS, "Calculate CPS unit keys...\n");

npzacs's avatar
npzacs committed
546
    fp = _open_unit_key_file(aacs->path);
npzacs's avatar
npzacs committed
547 548 549
    if (!fp) {
        return AACS_ERROR_CORRUPTED_DISC;
    }
cRTrn13's avatar
openssl  
cRTrn13 committed
550

npzacs's avatar
npzacs committed
551 552
    if ((file_read(fp, buf, 4)) == 4) {
        f_pos = MKINT_BE32(buf);
npzacs's avatar
npzacs committed
553

npzacs's avatar
npzacs committed
554 555 556 557
        // Read number of keys
        file_seek(fp, f_pos, SEEK_SET);
        if ((file_read(fp, buf, 2)) == 2) {
            aacs->num_uks = MKINT_BE16(buf);
npzacs's avatar
npzacs committed
558

npzacs's avatar
npzacs committed
559 560
            X_FREE(aacs->uks);
            aacs->uks = calloc(aacs->num_uks, 16);
npzacs's avatar
npzacs committed
561

npzacs's avatar
npzacs committed
562
            DEBUG(DBG_AACS, "%d CPS unit keys\n", aacs->num_uks);
npzacs's avatar
npzacs committed
563

npzacs's avatar
npzacs committed
564 565 566 567 568
        } else {
            aacs->num_uks = 0;
            DEBUG(DBG_AACS | DBG_CRIT, "Error reading number of unit keys\n");
            error_code = AACS_ERROR_CORRUPTED_DISC;
        }
cRTrn13's avatar
openssl  
cRTrn13 committed
569

npzacs's avatar
npzacs committed
570 571 572
        // Read keys
        for (i = 0; i < aacs->num_uks; i++) {
            f_pos += 48;
cRTrn13's avatar
openssl  
cRTrn13 committed
573

npzacs's avatar
npzacs committed
574 575 576 577 578 579
            file_seek(fp, f_pos, SEEK_SET);
            if ((file_read(fp, buf, 16)) != 16) {
                DEBUG(DBG_AACS, "Unit key %d: read error\n", i);
                aacs->num_uks = i;
                error_code = AACS_ERROR_CORRUPTED_DISC;
                break;
npzacs's avatar
npzacs committed
580
            }
cRTrn13's avatar
openssl  
cRTrn13 committed
581

npzacs's avatar
npzacs committed
582 583 584
            gcry_cipher_hd_t gcry_h;
            gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES,
                             GCRY_CIPHER_MODE_ECB, 0);
585
            gcry_cipher_setkey(gcry_h, vuk, 16);
npzacs's avatar
npzacs committed
586 587
            gcry_cipher_decrypt(gcry_h, aacs->uks + 16*i, 16, buf, 16);
            gcry_cipher_close(gcry_h);
cRTrn13's avatar
openssl  
cRTrn13 committed
588

npzacs's avatar
npzacs committed
589 590 591
            char str[40];
            DEBUG(DBG_AACS, "Unit key %d: %s\n", i,
                  print_hex(str, aacs->uks + 16*i, 16));
592 593
        }

npzacs's avatar
npzacs committed
594 595 596
        /* failing next is not fatal, it just slows down things */
        _read_uks_map(aacs, fp);

597
        file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
598

npzacs's avatar
npzacs committed
599 600 601 602 603 604 605
        return error_code;
    }

    file_close(fp);

    DEBUG(DBG_AACS | DBG_CRIT, "Error reading unit keys\n");
    return AACS_ERROR_CORRUPTED_DISC;
cRTrn13's avatar
openssl  
cRTrn13 committed
606 607
}

608 609
static int _calc_title_hash(const char *path, uint8_t *title_hash)
{
610
    AACS_FILE_H *fp = NULL;
611 612 613
    uint8_t *ukf_buf;
    char     str[48];
    int64_t  f_size;
npzacs's avatar
npzacs committed
614
    int      result = AACS_SUCCESS;
615

npzacs's avatar
npzacs committed
616 617 618
    fp = _open_unit_key_file(path);
    if (!fp) {
        return AACS_ERROR_CORRUPTED_DISC;
619 620 621 622 623 624 625 626
    }

    file_seek(fp, 0, SEEK_END);
    f_size = file_tell(fp);
    file_seek(fp, 0, SEEK_SET);

    ukf_buf = malloc(f_size);

npzacs's avatar
npzacs committed
627 628 629
    if ((file_read(fp, ukf_buf, f_size)) == f_size) {
        crypto_aacs_title_hash(ukf_buf, f_size, title_hash);
        DEBUG(DBG_AACS, "Disc ID: %s\n", print_hex(str, title_hash, 20));
cRTrn13's avatar
cRTrn13 committed
630

npzacs's avatar
npzacs committed
631 632 633
    } else {
        result = AACS_ERROR_CORRUPTED_DISC;
        DEBUG(DBG_AACS | DBG_CRIT, "Failed to read %"PRIu64" bytes from unit key file %s/AACS/Unit_Key_RO.inf", f_size, path);
634 635 636 637 638
    }

    file_close(fp);
    X_FREE(ukf_buf);

npzacs's avatar
npzacs committed
639
    return result;
640
}
cRTrn13's avatar
cRTrn13 committed
641

npzacs's avatar
npzacs committed
642
static int _verify_ts(uint8_t *buf, size_t size)
643
{
644 645
    uint8_t *ptr;

cRTrn13's avatar
cRTrn13 committed
646 647 648 649 650 651 652
    if (size < 192) {
        return 1;
    }

    for (ptr=buf; ptr < buf+192; ptr++) {
        int failed = 0;
        if (*ptr == 0x47) {
653 654 655 656
            uint8_t *ptr2;

            for (ptr2=ptr; ptr2 < buf + size; ptr2 += 192) {
                if (*ptr2 != 0x47) {
cRTrn13's avatar
cRTrn13 committed
657 658
                    failed = 1;
                    break;
659 660
                }
            }
cRTrn13's avatar
cRTrn13 committed
661 662 663
            if (!failed) {
                return 1;
            }
664 665 666 667
        }
        ptr++;
    }

cRTrn13's avatar
cRTrn13 committed
668
    DEBUG(DBG_AACS, "Failed to verify TS!\n");
669

cRTrn13's avatar
cRTrn13 committed
670
    return 0;
671 672
}

673
#define ALIGNED_UNIT_LEN 6144
674
static int _decrypt_unit(AACS *aacs, uint8_t *out_buf, const uint8_t *in_buf, uint32_t curr_uk)
cRTrn13's avatar
cRTrn13 committed
675
{
676 677 678 679 680 681 682
    gcry_cipher_hd_t gcry_h;
    int a;
    uint8_t key[16], iv[] = "\x0b\xa0\xf8\xdd\xfe\xa6\x1f\xb3"
                            "\xd8\xdf\x9f\x56\x6a\x05\x0f\x78";

    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
    gcry_cipher_setkey(gcry_h, aacs->uks + curr_uk * 16, 16);
683
    gcry_cipher_encrypt(gcry_h, key, 16, in_buf, 16);
684
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
685

cRTrn13's avatar
cRTrn13 committed
686
    for (a = 0; a < 16; a++) {
687
        key[a] ^= in_buf[a];
cRTrn13's avatar
cRTrn13 committed
688 689
    }

690 691
    memcpy(out_buf, in_buf, 16); /* first 16 bytes are plain */

692 693 694
    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
    gcry_cipher_setkey(gcry_h, key, 16);
    gcry_cipher_setiv(gcry_h, iv, 16);
695
    gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, in_buf + 16, ALIGNED_UNIT_LEN - 16);
696
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
697

698
    if (_verify_ts(out_buf, ALIGNED_UNIT_LEN)) {
cRTrn13's avatar
cRTrn13 committed
699 700 701
        return 1;
    }

702
    if (curr_uk < aacs->num_uks - 1) {
703
        return _decrypt_unit(aacs, out_buf, in_buf, curr_uk++);
npzacs's avatar
npzacs committed
704 705
    }

cRTrn13's avatar
cRTrn13 committed
706 707 708
    return 0;
}

npzacs's avatar
npzacs committed
709 710
void aacs_get_version(int *major, int *minor, int *micro)
{
npzacs's avatar
npzacs committed
711 712 713
    *major = AACS_VERSION_MAJOR;
    *minor = AACS_VERSION_MINOR;
    *micro = AACS_VERSION_MICRO;
npzacs's avatar
npzacs committed
714 715
}

npzacs's avatar
npzacs committed
716
/* aacs_open2() wrapper for backwards compability */
cRTrn13's avatar
cRTrn13 committed
717
AACS *aacs_open(const char *path, const char *configfile_path)
npzacs's avatar
npzacs committed
718 719 720 721 722 723 724 725 726 727 728 729 730 731
{
    int error_code;
    AACS *aacs;

    aacs = aacs_open2(path, configfile_path, &error_code);
    if (error_code == AACS_SUCCESS) {
        return aacs;
    }

    aacs_close(aacs);
    return NULL;
}

AACS *aacs_open2(const char *path, const char *configfile_path, int *error_code)
cRTrn13's avatar
cRTrn13 committed
732
{
npzacs's avatar
npzacs committed
733
    DEBUG(DBG_AACS, "libaacs "AACS_VERSION_STRING" [%zd]\n", sizeof(AACS));
cRTrn13's avatar
cRTrn13 committed
734

735
    DEBUG(DBG_AACS, "Initializing libgcrypt...\n");
npzacs's avatar
npzacs committed
736
    if (!crypto_init()) {
npzacs's avatar
npzacs committed
737
        DEBUG(DBG_AACS | DBG_CRIT, "Failed to initialize libgcrypt\n");
738 739
        return NULL;
    }
740

cRTrn13's avatar
cRTrn13 committed
741
    AACS *aacs = calloc(1, sizeof(AACS));
742

npzacs's avatar
npzacs committed
743 744
    aacs->path = str_printf("%s", path);

npzacs's avatar
npzacs committed
745 746 747 748 749
    *error_code = _calc_title_hash(path, aacs->disc_id);
    if (*error_code != AACS_SUCCESS) {
        aacs_close(aacs);
        return NULL;
    }
npzacs's avatar
npzacs committed
750

npzacs's avatar
npzacs committed
751
    DEBUG(DBG_AACS, "Starting AACS waterfall...\n");
752
    *error_code = _calc_uks(aacs, configfile_path);
cRTrn13's avatar
cRTrn13 committed
753

npzacs's avatar
npzacs committed
754
    if (*error_code == AACS_SUCCESS) {
755
        DEBUG(DBG_AACS, "AACS initialized!\n");
npzacs's avatar
npzacs committed
756
    } else {
757
        DEBUG(DBG_AACS, "Failed to initialize AACS!\n");
npzacs's avatar
npzacs committed
758
    }
759

npzacs's avatar
npzacs committed
760
    return aacs;
cRTrn13's avatar
cRTrn13 committed
761 762
}

cRTrn13's avatar
cRTrn13 committed
763
void aacs_close(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
764
{
npzacs's avatar
npzacs committed
765 766 767
    if (!aacs)
        return;

768
    X_FREE(aacs->uks);
769
    X_FREE(aacs->cps_units);
npzacs's avatar
npzacs committed
770
    X_FREE(aacs->path);
771

772
    DEBUG(DBG_AACS, "AACS destroyed!\n");
cRTrn13's avatar
cRTrn13 committed
773

cRTrn13's avatar
cRTrn13 committed
774 775 776
    X_FREE(aacs);
}

777
int aacs_decrypt_unit(AACS *aacs, uint8_t *buf)
778
{
779 780
    uint8_t out_buf[ALIGNED_UNIT_LEN];

781 782 783 784 785
    if (!(buf[0] & 0xc0)) {
        // TP_extra_header Copy_permission_indicator == 0, unit is not encrypted
        return 1;
    }

786
    if (_decrypt_unit(aacs, out_buf, buf, aacs->current_cps_unit)) {
787
        memcpy(buf, out_buf, ALIGNED_UNIT_LEN);
788 789 790 791 792 793 794

        // Clear copy_permission_indicator bits
        int i;
        for (i = 0; i < 6144; i += 192) {
            buf[i] &= ~0xc0;
        }

795 796 797
        return 1;
    }

798
    DEBUG(DBG_AACS, "Failed decrypting unit [6144 bytes]\n");
799

800
    return 0;
801
}
cRTrn13's avatar
cRTrn13 committed
802

npzacs's avatar
npzacs committed
803 804 805 806 807 808 809 810 811 812 813 814
int aacs_get_mkb_version(AACS *aacs)
{
    if (!aacs->mkb_version) {
        MKB *mkb;
        if ((mkb = mkb_open(aacs->path))) {
            aacs->mkb_version = mkb_version(mkb);
            mkb_close(mkb);
        }
    }
    return aacs->mkb_version;
}

npzacs's avatar
npzacs committed
815 816 817 818 819
const uint8_t *aacs_get_disc_id(AACS *aacs)
{
    return aacs->disc_id;
}

820
const uint8_t *aacs_get_vid(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
821
{
822
    if (!memcmp(aacs->vid, empty_key, 16)) {
npzacs's avatar
npzacs committed
823 824 825 826 827 828
        /* get cached vid */
        if (keycache_find("vid", aacs->disc_id, aacs->vid, 16)) {
            DEBUG(DBG_AACS, "Using cached VID\n");
            return aacs->vid;
        }

829 830
        config_file *cf = keydbcfg_config_load(NULL);
        if (cf) {
831
            _read_vid(aacs, cf->host_cert_list, 0);
832 833 834 835

            keydbcfg_config_file_close(cf);
        }
    }
836 837 838 839 840 841

    if (!memcmp(aacs->vid, empty_key, 16)) {
        DEBUG(DBG_AACS | DBG_CRIT, "aacs_get_vid() failed\n");
        return NULL;
    }

cRTrn13's avatar
cRTrn13 committed
842 843
    return aacs->vid;
}
844

845 846
const uint8_t *aacs_get_pmsn(AACS *aacs)
{
npzacs's avatar
npzacs committed
847
    if (!memcmp(aacs->pmsn, empty_key, 16)) {
848 849
        config_file *cf = keydbcfg_config_load(NULL);
        if (cf) {
850
            _read_vid(aacs, cf->host_cert_list, 1);
851 852 853 854

            keydbcfg_config_file_close(cf);
        }
    }
855 856 857 858 859 860

    if (!memcmp(aacs->pmsn, empty_key, 16)) {
        DEBUG(DBG_AACS, "aacs_get_pmsn() failed\n");
        return NULL;
    }

861 862 863
    return aacs->pmsn;
}

npzacs's avatar
npzacs committed
864
static AACS_RL_ENTRY *_get_rl(const char *type, int *num_records, int *mkbv)
npzacs's avatar
npzacs committed
865 866 867 868
{
    uint32_t len, version;
    void *data = NULL;

npzacs's avatar
npzacs committed
869
    *num_records = *mkbv = 0;
npzacs's avatar
npzacs committed
870 871 872 873 874 875 876 877

    cache_get(type, &version, &len, NULL);

    if (version > 0 && len > 24) {
        data = malloc(len);
        if (cache_get(type, &version, &len, data) && len > 24) {

            if (_rl_verify_signature(data, len)) {
npzacs's avatar
npzacs committed
878
                *mkbv = version;
npzacs's avatar
npzacs committed
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
                *num_records = MKINT_BE32((uint8_t*)data + 20);
                memmove(data, (uint8_t*)data + 24, len - 24);

                int ii;
                AACS_RL_ENTRY *rl = data;
                for (ii = 0; ii < *num_records; ii++) {
                    rl[ii].range = MKINT_BE16((uint8_t*)&rl[ii].range);
                }

                return rl;
            }

            DEBUG(DBG_AACS | DBG_CRIT, "invalid signature in cached %s\n", type);
        }

        X_FREE(data);
    }

    return data;
}

npzacs's avatar
npzacs committed
900
AACS_RL_ENTRY *aacs_get_hrl(int *num_records, int *mkbv)
npzacs's avatar
npzacs committed
901
{
npzacs's avatar
npzacs committed
902
    return _get_rl("hrl", num_records, mkbv);