aacs.c 20.1 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
    /* configuration data */
    config_file *cf;
50

npzacs's avatar
npzacs committed
51 52 53 54 55 56 57 58 59 60 61
    /* current disc */
    char     *path;
    int       mkb_version;
    uint8_t   disc_id[20];

    /* disc keys */
    uint8_t   mk[16], vuk[16], vid[16];

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

npzacs's avatar
npzacs committed
63 64 65 66 67 68
    /* 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
69 70
};

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

74 75
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
76
                        uint8_t *mk)
cRTrn13's avatar
cRTrn13 committed
77
{
78
    gcry_cipher_hd_t gcry_h;
npzacs's avatar
npzacs committed
79
    int a;
cRTrn13's avatar
cRTrn13 committed
80
    uint8_t dec_vd[16];
81
    char str[40];
cRTrn13's avatar
cRTrn13 committed
82

83
    DEBUG(DBG_AACS, "Validate processing key %s...\n", print_hex(str, pk, 16));
cRTrn13's avatar
cRTrn13 committed
84
    DEBUG(DBG_AACS, " Using:\n");
85 86 87
    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));
88

89 90 91
    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);
92

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

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

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

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

npzacs's avatar
npzacs committed
109
static int _calc_mk(AACS *aacs)
cRTrn13's avatar
keyfile  
cRTrn13 committed
110 111 112
{
    int a, num_uvs = 0;
    size_t len;
113
    uint8_t *buf = NULL;
cRTrn13's avatar
keyfile  
cRTrn13 committed
114
    MKB *mkb = NULL;
115
    const uint8_t *rec, *uvs;
cRTrn13's avatar
keyfile  
cRTrn13 committed
116

117 118
    /* Skip if retrieved from config file */
    if (memcmp(aacs->mk, empty_key, 16))
npzacs's avatar
npzacs committed
119
      return AACS_SUCCESS;
120

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

npzacs's avatar
npzacs committed
123
    if ((mkb = mkb_open(aacs->path))) {
124
        DEBUG(DBG_AACS, "Get UVS...\n");
npzacs's avatar
npzacs committed
125
        aacs->mkb_version = mkb_version(mkb);
126 127 128 129 130 131 132 133
        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
134

135 136
        DEBUG(DBG_AACS, "Get cvalues...\n");
        rec = mkb_cvalues(mkb, &len);
137 138 139
        if (aacs->cf->pkl) {
            pk_list *pkcursor = aacs->cf->pkl;
            while (pkcursor && pkcursor->key) {
140 141
                uint8_t pk[16];
                hexstring_to_hex_array(pk, sizeof(pk), pkcursor->key);
142 143 144
                DEBUG(DBG_AACS, "Trying processing key...\n");

                for (a = 0; a < num_uvs; a++) {
145
                    if (AACS_SUCCESS == _validate_pk(pk, rec + a * 16, uvs + 1 + a * 5,
gates's avatar
gates committed
146
                      mkb_mk_dv(mkb), aacs->mk)) {
147 148
                        mkb_close(mkb);
                        X_FREE(buf);
149

150 151
                        char str[40];
                        DEBUG(DBG_AACS, "Media key: %s\n", print_hex(str, aacs->mk,
gates's avatar
gates committed
152
                                                                     16));
npzacs's avatar
npzacs committed
153
                        return AACS_SUCCESS;
154 155 156
                    }
                }

157
                pkcursor = pkcursor->next;
cRTrn13's avatar
keyfile  
cRTrn13 committed
158
            }
159
        }
cRTrn13's avatar
keyfile  
cRTrn13 committed
160

161 162
        mkb_close(mkb);
        X_FREE(buf);
cRTrn13's avatar
keyfile  
cRTrn13 committed
163

npzacs's avatar
npzacs committed
164
        DEBUG(DBG_AACS | DBG_CRIT, "Error calculating media key. Missing right processing key ?\n");
npzacs's avatar
npzacs committed
165
        return AACS_ERROR_NO_PK;
npzacs's avatar
npzacs committed
166
    }
npzacs's avatar
npzacs committed
167

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

npzacs's avatar
npzacs committed
172
static int _read_vid(AACS *aacs)
cRTrn13's avatar
openssl  
cRTrn13 committed
173
{
174 175
    /* Use VID given in config file if available */
    if (memcmp(aacs->vid, empty_key, 16)) {
npzacs's avatar
npzacs committed
176
        return AACS_SUCCESS;
177 178
    }

cRTrn13's avatar
cRTrn13 committed
179
    MMC* mmc = NULL;
npzacs's avatar
npzacs committed
180
    if (!(mmc = mmc_open(aacs->path))) {
npzacs's avatar
npzacs committed
181
        return AACS_ERROR_MMC_OPEN;
182 183
    }

npzacs's avatar
npzacs committed
184 185
    int error_code = AACS_ERROR_NO_CERT;

186 187 188 189 190 191 192 193 194
    cert_list *hccursor = aacs->cf->host_cert_list;
    while (hccursor && hccursor->host_priv_key && hccursor->host_cert) {

        char tmp_str[2*92+1];
        uint8_t priv_key[20], cert[92];
        hexstring_to_hex_array(priv_key, sizeof(priv_key), hccursor->host_priv_key);
        hexstring_to_hex_array(cert,     sizeof(cert),     hccursor->host_cert);

        if (!crypto_aacs_verify_host_cert(cert)) {
npzacs's avatar
npzacs committed
195 196
            DEBUG(DBG_AACS, "Not using invalid host certificate %s.\n",
                  print_hex(tmp_str, cert, 92));
197

npzacs's avatar
npzacs committed
198 199 200
            hccursor = hccursor->next;
            continue;
        }
201 202 203 204

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

npzacs's avatar
npzacs committed
205
        int mmc_result = mmc_read_vid(mmc, priv_key, cert, aacs->vid);
npzacs's avatar
npzacs committed
206 207 208 209 210 211 212 213 214 215 216
        switch (mmc_result) {
            case MMC_SUCCESS:
                mmc_close(mmc);
                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;
217 218 219 220 221 222 223 224
        }

        hccursor = hccursor->next;
    }

    mmc_close(mmc);

    DEBUG(DBG_AACS, "Error reading VID!\n");
npzacs's avatar
npzacs committed
225
    return error_code;
226
}
cRTrn13's avatar
openssl  
cRTrn13 committed
227

npzacs's avatar
npzacs committed
228
static int _calc_vuk(AACS *aacs)
229
{
npzacs's avatar
npzacs committed
230 231
    int error_code;

232
    /* Skip if retrieved from config file */
npzacs's avatar
npzacs committed
233 234 235 236
    if (memcmp(aacs->vuk, empty_key, 16)) {
        DEBUG(DBG_AACS, "Using VUK from config file\n");
        return AACS_SUCCESS;
    }
237

npzacs's avatar
npzacs committed
238 239 240
    /* get cached vuk */
    if (keycache_find("vuk", aacs->disc_id, aacs->vuk, 16)) {
        DEBUG(DBG_AACS, "Using cached VUK\n");
npzacs's avatar
npzacs committed
241
        return AACS_SUCCESS;
npzacs's avatar
npzacs committed
242 243
    }

244
    /* make sure we have media key */
npzacs's avatar
npzacs committed
245
    error_code = _calc_mk(aacs);
npzacs's avatar
npzacs committed
246 247
    if (error_code != AACS_SUCCESS) {
        return error_code;
248 249
    }

npzacs's avatar
npzacs committed
250
    /* acquire VID */
npzacs's avatar
npzacs committed
251
    error_code = _read_vid(aacs);
npzacs's avatar
npzacs committed
252 253 254
    if (error_code != AACS_SUCCESS) {
        return error_code;
    }
255

npzacs's avatar
npzacs committed
256 257
    int a;
    gcry_cipher_hd_t gcry_h;
258

npzacs's avatar
npzacs committed
259 260 261 262
    gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0);
    gcry_cipher_setkey(gcry_h, aacs->mk, 16);
    gcry_cipher_decrypt(gcry_h, aacs->vuk, 16, aacs->vid, 16);
    gcry_cipher_close(gcry_h);
263

npzacs's avatar
npzacs committed
264 265 266
    for (a = 0; a < 16; a++) {
        aacs->vuk[a] ^= aacs->vid[a];
    }
267

npzacs's avatar
npzacs committed
268 269
    char str[40];
    DEBUG(DBG_AACS, "Volume unique key: %s\n", print_hex(str, aacs->vuk, 16));
270

npzacs's avatar
npzacs committed
271 272
    /* cache vuk */
    keycache_save("vuk", aacs->disc_id, aacs->vuk, 16);
npzacs's avatar
npzacs committed
273

npzacs's avatar
npzacs committed
274
    return AACS_SUCCESS;
cRTrn13's avatar
openssl  
cRTrn13 committed
275 276
}

277 278
static uint16_t _read_u16(AACS_FILE_H *fp)
{
npzacs's avatar
npzacs committed
279
  uint8_t data[2] = {0, 0};
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325

  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
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
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
342
static int _calc_uks(AACS *aacs)
cRTrn13's avatar
openssl  
cRTrn13 committed
343
{
344
    AACS_FILE_H *fp = NULL;
345
    uint8_t  buf[16];
346
    uint64_t f_pos;
347
    unsigned int i;
npzacs's avatar
npzacs committed
348
    int error_code;
cRTrn13's avatar
openssl  
cRTrn13 committed
349

350 351
    /* Skip if retrieved from config file */
    if (aacs->uks)
npzacs's avatar
npzacs committed
352
        return AACS_SUCCESS;
353

354
    /* Make sure we have VUK */
npzacs's avatar
npzacs committed
355
    error_code = _calc_vuk(aacs);
npzacs's avatar
npzacs committed
356 357
    if (error_code != AACS_SUCCESS) {
        return error_code;
358
    }
359

360 361
    DEBUG(DBG_AACS, "Calculate CPS unit keys...\n");

npzacs's avatar
npzacs committed
362
    fp = _open_unit_key_file(aacs->path);
npzacs's avatar
npzacs committed
363 364 365
    if (!fp) {
        return AACS_ERROR_CORRUPTED_DISC;
    }
cRTrn13's avatar
openssl  
cRTrn13 committed
366

npzacs's avatar
npzacs committed
367 368
    if ((file_read(fp, buf, 4)) == 4) {
        f_pos = MKINT_BE32(buf);
npzacs's avatar
npzacs committed
369

npzacs's avatar
npzacs committed
370 371 372 373
        // 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
374

npzacs's avatar
npzacs committed
375 376
            X_FREE(aacs->uks);
            aacs->uks = calloc(aacs->num_uks, 16);
npzacs's avatar
npzacs committed
377

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

npzacs's avatar
npzacs committed
380 381 382 383 384
        } 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
385

npzacs's avatar
npzacs committed
386 387 388
        // Read keys
        for (i = 0; i < aacs->num_uks; i++) {
            f_pos += 48;
cRTrn13's avatar
openssl  
cRTrn13 committed
389

npzacs's avatar
npzacs committed
390 391 392 393 394 395
            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
396
            }
cRTrn13's avatar
openssl  
cRTrn13 committed
397

npzacs's avatar
npzacs committed
398 399 400 401 402 403
            gcry_cipher_hd_t gcry_h;
            gcry_cipher_open(&gcry_h, GCRY_CIPHER_AES,
                             GCRY_CIPHER_MODE_ECB, 0);
            gcry_cipher_setkey(gcry_h, aacs->vuk, 16);
            gcry_cipher_decrypt(gcry_h, aacs->uks + 16*i, 16, buf, 16);
            gcry_cipher_close(gcry_h);
cRTrn13's avatar
openssl  
cRTrn13 committed
404

npzacs's avatar
npzacs committed
405 406 407
            char str[40];
            DEBUG(DBG_AACS, "Unit key %d: %s\n", i,
                  print_hex(str, aacs->uks + 16*i, 16));
408 409
        }

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

413
        file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
414

npzacs's avatar
npzacs committed
415 416 417 418 419 420 421
        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
422 423
}

424 425
static int _calc_title_hash(const char *path, uint8_t *title_hash)
{
426
    AACS_FILE_H *fp = NULL;
427 428 429
    uint8_t *ukf_buf;
    char     str[48];
    int64_t  f_size;
npzacs's avatar
npzacs committed
430
    int      result = AACS_SUCCESS;
431

npzacs's avatar
npzacs committed
432 433 434
    fp = _open_unit_key_file(path);
    if (!fp) {
        return AACS_ERROR_CORRUPTED_DISC;
435 436 437 438 439 440 441 442
    }

    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
443 444 445
    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
446

npzacs's avatar
npzacs committed
447 448 449
    } 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);
450 451 452 453 454
    }

    file_close(fp);
    X_FREE(ukf_buf);

npzacs's avatar
npzacs committed
455
    return result;
456
}
cRTrn13's avatar
cRTrn13 committed
457

npzacs's avatar
npzacs committed
458
static int _verify_ts(uint8_t *buf, size_t size)
459
{
460 461
    uint8_t *ptr;

cRTrn13's avatar
cRTrn13 committed
462 463 464 465 466 467 468
    if (size < 192) {
        return 1;
    }

    for (ptr=buf; ptr < buf+192; ptr++) {
        int failed = 0;
        if (*ptr == 0x47) {
469 470 471 472
            uint8_t *ptr2;

            for (ptr2=ptr; ptr2 < buf + size; ptr2 += 192) {
                if (*ptr2 != 0x47) {
cRTrn13's avatar
cRTrn13 committed
473 474
                    failed = 1;
                    break;
475 476
                }
            }
cRTrn13's avatar
cRTrn13 committed
477 478 479
            if (!failed) {
                return 1;
            }
480 481 482 483
        }
        ptr++;
    }

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

cRTrn13's avatar
cRTrn13 committed
486
    return 0;
487 488
}

489
/* Function that collects keys from keydb config entry */
490
static void _find_config_entry(AACS *aacs)
491
{
npzacs's avatar
npzacs committed
492
    uint8_t discid[20];
493
    char str[48];
npzacs's avatar
npzacs committed
494

495 496
    aacs->uks = NULL;
    aacs->num_uks = 0;
cRTrn13's avatar
cRTrn13 committed
497

npzacs's avatar
npzacs committed
498
    if (aacs->cf && aacs->cf->list) {
499 500 501
        struct title_entry_list_t *ce;
        ce = aacs->cf->list;
        while (ce && ce->entry.discid) {
502 503
            memset(discid, 0, sizeof(discid));
            hexstring_to_hex_array(discid, sizeof(discid),
504
                                   ce->entry.discid);
npzacs's avatar
npzacs committed
505
            if (!memcmp(aacs->disc_id, discid, 20)) {
506
                DEBUG(DBG_AACS, "Found config entry for discid %s\n",
507
                      ce->entry.discid);
508
                break;
509 510
            }

511 512 513 514
            ce = ce->next;
        }
        if (!ce) {
            return;
515
        }
516

517
        if (ce->entry.mek) {
518
            hexstring_to_hex_array(aacs->mk, sizeof(aacs->mk),
519
                                   ce->entry.mek);
520 521

            DEBUG(DBG_AACS, "Found media key for %s: %s\n",
522
                  ce->entry.discid, print_hex(str, aacs->mk, 16));
523 524
        }

525
        if (ce->entry.vid) {
526
            hexstring_to_hex_array(aacs->vid, sizeof(aacs->vid),
527
                                    ce->entry.vid);
528 529

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

533
        if (ce->entry.vuk) {
534
            hexstring_to_hex_array(aacs->vuk, sizeof(aacs->vuk),
535
                                    ce->entry.vuk);
536 537

            DEBUG(DBG_AACS, "Found volume unique key for %s: %s\n",
538
                  ce->entry.discid, print_hex(str, aacs->vuk, 16));
539 540
        }

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

544
            digit_key_pair_list *ukcursor = ce->entry.uk;
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
            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);

                char str[40];
                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;
            }
        }
560
    }
561 562
}

563
#define ALIGNED_UNIT_LEN 6144
564
static int _decrypt_unit(AACS *aacs, uint8_t *out_buf, const uint8_t *in_buf, uint32_t curr_uk)
cRTrn13's avatar
cRTrn13 committed
565
{
566 567 568 569 570 571 572
    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);
573
    gcry_cipher_encrypt(gcry_h, key, 16, in_buf, 16);
574
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
575

cRTrn13's avatar
cRTrn13 committed
576
    for (a = 0; a < 16; a++) {
577
        key[a] ^= in_buf[a];
cRTrn13's avatar
cRTrn13 committed
578 579
    }

580 581
    memcpy(out_buf, in_buf, 16); /* first 16 bytes are plain */

582 583 584
    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);
585
    gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, in_buf + 16, ALIGNED_UNIT_LEN - 16);
586
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
587

588
    if (_verify_ts(out_buf, ALIGNED_UNIT_LEN)) {
cRTrn13's avatar
cRTrn13 committed
589 590 591
        return 1;
    }

592
    if (curr_uk < aacs->num_uks - 1) {
593
        return _decrypt_unit(aacs, out_buf, in_buf, curr_uk++);
npzacs's avatar
npzacs committed
594 595
    }

cRTrn13's avatar
cRTrn13 committed
596 597 598
    return 0;
}

npzacs's avatar
npzacs committed
599 600
void aacs_get_version(int *major, int *minor, int *micro)
{
npzacs's avatar
npzacs committed
601 602 603
    *major = AACS_VERSION_MAJOR;
    *minor = AACS_VERSION_MINOR;
    *micro = AACS_VERSION_MICRO;
npzacs's avatar
npzacs committed
604 605
}

npzacs's avatar
npzacs committed
606
/* aacs_open2() wrapper for backwards compability */
cRTrn13's avatar
cRTrn13 committed
607
AACS *aacs_open(const char *path, const char *configfile_path)
npzacs's avatar
npzacs committed
608 609 610 611 612 613 614 615 616 617 618 619 620 621
{
    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
622
{
npzacs's avatar
npzacs committed
623
    DEBUG(DBG_AACS, "libaacs "AACS_VERSION_STRING" [%zd]\n", sizeof(AACS));
cRTrn13's avatar
cRTrn13 committed
624

625
    DEBUG(DBG_AACS, "Initializing libgcrypt...\n");
npzacs's avatar
npzacs committed
626
    if (!crypto_init()) {
npzacs's avatar
npzacs committed
627
        DEBUG(DBG_AACS | DBG_CRIT, "Failed to initialize libgcrypt\n");
628 629
        return NULL;
    }
630

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

npzacs's avatar
npzacs committed
633 634
    aacs->cf = keydbcfg_config_load(configfile_path);
    if (!aacs->cf) {
635
        aacs_close(aacs);
npzacs's avatar
npzacs committed
636
        *error_code = AACS_ERROR_NO_CONFIG;
637 638 639
        return NULL;
    }

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

npzacs's avatar
npzacs committed
642 643 644 645 646
    *error_code = _calc_title_hash(path, aacs->disc_id);
    if (*error_code != AACS_SUCCESS) {
        aacs_close(aacs);
        return NULL;
    }
npzacs's avatar
npzacs committed
647

npzacs's avatar
npzacs committed
648 649
    DEBUG(DBG_AACS, "Searching for keydb config entry...\n");
    _find_config_entry(aacs);
650

npzacs's avatar
npzacs committed
651
    DEBUG(DBG_AACS, "Starting AACS waterfall...\n");
npzacs's avatar
npzacs committed
652
    *error_code = _calc_uks(aacs);
cRTrn13's avatar
cRTrn13 committed
653

npzacs's avatar
npzacs committed
654 655
    keydbcfg_config_file_close(aacs->cf);
    aacs->cf = NULL;
cRTrn13's avatar
cRTrn13 committed
656

npzacs's avatar
npzacs committed
657 658 659 660 661
    if (*error_code == AACS_SUCCESS) {
        DEBUG(DBG_AACS, "AACS initialized! (%p)\n", aacs);
    } else {
        DEBUG(DBG_AACS, "Failed to initialize AACS! (%p)\n", aacs);
    }
662

npzacs's avatar
npzacs committed
663
    return aacs;
cRTrn13's avatar
cRTrn13 committed
664 665
}

cRTrn13's avatar
cRTrn13 committed
666
void aacs_close(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
667
{
npzacs's avatar
npzacs committed
668 669 670
    if (!aacs)
        return;

npzacs's avatar
npzacs committed
671 672 673 674 675
    if (aacs->cf) {
        keydbcfg_config_file_close(aacs->cf);
        aacs->cf = NULL;
    }

676
    X_FREE(aacs->uks);
677
    X_FREE(aacs->cps_units);
npzacs's avatar
npzacs committed
678
    X_FREE(aacs->path);
679

npzacs's avatar
npzacs committed
680
    DEBUG(DBG_AACS, "AACS destroyed! (%p)\n", aacs);
cRTrn13's avatar
cRTrn13 committed
681

cRTrn13's avatar
cRTrn13 committed
682 683 684
    X_FREE(aacs);
}

685
int aacs_decrypt_unit(AACS *aacs, uint8_t *buf)
686
{
687 688
    uint8_t out_buf[ALIGNED_UNIT_LEN];

689 690 691 692 693
    if (!(buf[0] & 0xc0)) {
        // TP_extra_header Copy_permission_indicator == 0, unit is not encrypted
        return 1;
    }

694
    if (_decrypt_unit(aacs, out_buf, buf, aacs->current_cps_unit)) {
695
        memcpy(buf, out_buf, ALIGNED_UNIT_LEN);
696 697 698 699 700 701 702

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

703 704 705
        return 1;
    }

706
    DEBUG(DBG_AACS, "Failed decrypting unit [6144 bytes] (%p)\n", aacs);
707

708
    return 0;
709
}
cRTrn13's avatar
cRTrn13 committed
710

npzacs's avatar
npzacs committed
711 712 713 714 715 716 717 718 719 720 721 722
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
723 724 725 726 727
const uint8_t *aacs_get_disc_id(AACS *aacs)
{
    return aacs->disc_id;
}

728
const uint8_t *aacs_get_vid(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
729 730 731
{
    return aacs->vid;
}
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758

void aacs_select_title(AACS *aacs, uint32_t title)
{
    if (!aacs) {
        return;
    }

    if (!aacs->cps_units) {
        DEBUG(DBG_AACS|DBG_CRIT, "aacs_select_title(): CPS units not read ! (%p)\n", aacs);
        return;
    }

    if (title == 0xffff) {
        /* first play */
        aacs->current_cps_unit = aacs->cps_units[0];
        DEBUG(DBG_AACS, "aacs_set_title(first_play): CPS unit %d (%p)\n", aacs->current_cps_unit, aacs);
        return;
    }

    if (title <= aacs->num_titles) {
        aacs->current_cps_unit = aacs->cps_units[title + 1];
        DEBUG(DBG_AACS, "aacs_set_title(%d): CPS unit %d (%p)\n", title, aacs->current_cps_unit, aacs);
        return;
    }

    DEBUG(DBG_AACS|DBG_CRIT, "aacs_set_title(%d): invalid title ! (%p)\n", title, aacs);
}