aacs.c 20.6 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
    uint8_t pk[16], mk[16], vuk[16], vid[16], disc_id[20], *uks;
npzacs's avatar
npzacs committed
49 50
    uint32_t num_uks;
    struct config_file_t *cf;
51
    struct title_entry_list_t *ce;
52 53 54 55

    uint32_t num_titles;
    uint16_t current_cps_unit;
    uint16_t *cps_units;  /* [0] = first play ; [1] = top menu ; [2] = title 1 ... */
npzacs's avatar
npzacs committed
56 57
};

58 59 60
static const uint8_t empty_key[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
                                   "\x00\x00\x00\x00\x00\x00\x00\x00";

61 62
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
63
                        uint8_t *mk)
cRTrn13's avatar
cRTrn13 committed
64
{
65
    gcry_cipher_hd_t gcry_h;
npzacs's avatar
npzacs committed
66
    int a;
cRTrn13's avatar
cRTrn13 committed
67
    uint8_t dec_vd[16];
68
    char str[40];
cRTrn13's avatar
cRTrn13 committed
69

70
    DEBUG(DBG_AACS, "Validate processing key %s...\n", print_hex(str, pk, 16));
cRTrn13's avatar
cRTrn13 committed
71
    DEBUG(DBG_AACS, " Using:\n");
72 73 74
    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));
75

76 77 78
    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);
79

cRTrn13's avatar
cRTrn13 committed
80 81 82 83
    for (a = 0; a < 4; a++) {
        mk[a + 12] ^= uv[a];
    }

84 85 86
    gcry_cipher_setkey(gcry_h, mk, 16);
    gcry_cipher_decrypt (gcry_h, dec_vd, 16, vd, 16);
    gcry_cipher_close(gcry_h);
87

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

npzacs's avatar
npzacs committed
93
    return AACS_ERROR_NO_PK;
cRTrn13's avatar
cRTrn13 committed
94
}
95

npzacs's avatar
npzacs committed
96
static int _calc_mk(AACS *aacs, const char *path)
cRTrn13's avatar
keyfile  
cRTrn13 committed
97 98 99
{
    int a, num_uvs = 0;
    size_t len;
100
    uint8_t *buf = NULL;
cRTrn13's avatar
keyfile  
cRTrn13 committed
101
    MKB *mkb = NULL;
102
    const uint8_t *rec, *uvs;
cRTrn13's avatar
keyfile  
cRTrn13 committed
103

104 105
    /* Skip if retrieved from config file */
    if (memcmp(aacs->mk, empty_key, 16))
npzacs's avatar
npzacs committed
106
      return AACS_SUCCESS;
107

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

110 111 112 113 114 115 116 117 118 119
    if ((mkb = mkb_open(path))) {
        DEBUG(DBG_AACS, "Get UVS...\n");
        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
120

121 122
        DEBUG(DBG_AACS, "Get cvalues...\n");
        rec = mkb_cvalues(mkb, &len);
123 124 125 126 127
        if (aacs->cf->pkl) {
            pk_list *pkcursor = aacs->cf->pkl;
            while (pkcursor && pkcursor->key) {
                hexstring_to_hex_array(aacs->pk, sizeof(aacs->pk),
                                       pkcursor->key);
128 129 130
                DEBUG(DBG_AACS, "Trying processing key...\n");

                for (a = 0; a < num_uvs; a++) {
npzacs's avatar
npzacs committed
131
                    if (AACS_SUCCESS == _validate_pk(aacs->pk, rec + a * 16, uvs + 1 + a * 5,
gates's avatar
gates committed
132
                      mkb_mk_dv(mkb), aacs->mk)) {
133 134
                        mkb_close(mkb);
                        X_FREE(buf);
135

136 137
                        char str[40];
                        DEBUG(DBG_AACS, "Media key: %s\n", print_hex(str, aacs->mk,
gates's avatar
gates committed
138
                                                                     16));
npzacs's avatar
npzacs committed
139
                        return AACS_SUCCESS;
140 141 142
                    }
                }

143
                pkcursor = pkcursor->next;
cRTrn13's avatar
keyfile  
cRTrn13 committed
144
            }
145
        }
cRTrn13's avatar
keyfile  
cRTrn13 committed
146

147 148
        mkb_close(mkb);
        X_FREE(buf);
cRTrn13's avatar
keyfile  
cRTrn13 committed
149

npzacs's avatar
npzacs committed
150
        DEBUG(DBG_AACS | DBG_CRIT, "Error calculating media key. Missing right processing key ?\n");
npzacs's avatar
npzacs committed
151
        return AACS_ERROR_NO_PK;
npzacs's avatar
npzacs committed
152
    }
npzacs's avatar
npzacs committed
153

npzacs's avatar
npzacs committed
154
    DEBUG(DBG_AACS | DBG_CRIT, "Error opening %s/AACS/MKB_RO.inf\n", path);
npzacs's avatar
npzacs committed
155
    return AACS_ERROR_CORRUPTED_DISC;
cRTrn13's avatar
keyfile  
cRTrn13 committed
156
}
157

158
static int _read_vid(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
159
{
160 161
    /* Use VID given in config file if available */
    if (memcmp(aacs->vid, empty_key, 16)) {
npzacs's avatar
npzacs committed
162
        return AACS_SUCCESS;
163 164
    }

cRTrn13's avatar
cRTrn13 committed
165
    MMC* mmc = NULL;
166
    if (!(mmc = mmc_open(path))) {
npzacs's avatar
npzacs committed
167
        return AACS_ERROR_MMC_OPEN;
168 169
    }

npzacs's avatar
npzacs committed
170 171
    int error_code = AACS_ERROR_NO_CERT;

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    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)) {
	    DEBUG(DBG_AACS, "Not using invalid host certificate %s.\n",
		  print_hex(tmp_str, cert, 92));

	    hccursor = hccursor->next;
	    continue;
	}

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

npzacs's avatar
npzacs committed
191
        int mmc_result = mmc_read_vid(mmc, priv_key, cert, aacs->vid);
npzacs's avatar
npzacs committed
192 193 194 195 196 197 198 199 200 201 202
        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;
203 204 205 206 207 208 209 210
        }

        hccursor = hccursor->next;
    }

    mmc_close(mmc);

    DEBUG(DBG_AACS, "Error reading VID!\n");
npzacs's avatar
npzacs committed
211
    return error_code;
212
}
cRTrn13's avatar
openssl  
cRTrn13 committed
213

214 215
static int _calc_vuk(AACS *aacs, const char *path)
{
npzacs's avatar
npzacs committed
216 217
    int error_code;

218
    /* Skip if retrieved from config file */
npzacs's avatar
npzacs committed
219 220 221 222
    if (memcmp(aacs->vuk, empty_key, 16)) {
        DEBUG(DBG_AACS, "Using VUK from config file\n");
        return AACS_SUCCESS;
    }
223

npzacs's avatar
npzacs committed
224 225 226
    /* 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
227
        return AACS_SUCCESS;
npzacs's avatar
npzacs committed
228 229
    }

230
    /* make sure we have media key */
npzacs's avatar
npzacs committed
231 232 233
    error_code = _calc_mk(aacs, path);
    if (error_code != AACS_SUCCESS) {
        return error_code;
234 235
    }

npzacs's avatar
npzacs committed
236 237 238 239 240
    /* acquire VID */
    error_code = _read_vid(aacs, path);
    if (error_code != AACS_SUCCESS) {
        return error_code;
    }
241 242

        int a;
243
        gcry_cipher_hd_t gcry_h;
244

245 246 247 248 249 250 251 252 253 254
        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);

        for (a = 0; a < 16; a++) {
            aacs->vuk[a] ^= aacs->vid[a];
        }

        char str[40];
255
        DEBUG(DBG_AACS, "Volume unique key: %s\n", print_hex(str, aacs->vuk, 16));
256

npzacs's avatar
npzacs committed
257 258 259
        /* cache vuk */
        keycache_save("vuk", aacs->disc_id, aacs->vuk, 16);

npzacs's avatar
npzacs committed
260
        return AACS_SUCCESS;
cRTrn13's avatar
openssl  
cRTrn13 committed
261 262
}

263 264
static uint16_t _read_u16(AACS_FILE_H *fp)
{
npzacs's avatar
npzacs committed
265
  uint8_t data[2] = {0, 0};
266 267 268 269 270 271 272 273 274 275 276 277 278 279 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

  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
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
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
328
static int _calc_uks(AACS *aacs, const char *path)
cRTrn13's avatar
openssl  
cRTrn13 committed
329
{
330
    AACS_FILE_H *fp = NULL;
331
    uint8_t  buf[16];
332
    uint64_t f_pos;
333
    unsigned int i;
npzacs's avatar
npzacs committed
334
    int error_code;
cRTrn13's avatar
openssl  
cRTrn13 committed
335

336 337
    /* Skip if retrieved from config file */
    if (aacs->uks)
npzacs's avatar
npzacs committed
338
        return AACS_SUCCESS;
339

340
    /* Make sure we have VUK */
npzacs's avatar
npzacs committed
341 342 343
    error_code = _calc_vuk(aacs, path);
    if (error_code != AACS_SUCCESS) {
        return error_code;
344
    }
345

346 347
    DEBUG(DBG_AACS, "Calculate CPS unit keys...\n");

npzacs's avatar
npzacs committed
348 349 350 351
    fp = _open_unit_key_file(path);
    if (!fp) {
        return AACS_ERROR_CORRUPTED_DISC;
    }
cRTrn13's avatar
openssl  
cRTrn13 committed
352

353
        if ((file_read(fp, buf, 4)) == 4) {
npzacs's avatar
npzacs committed
354
            f_pos = MKINT_BE32(buf);
cRTrn13's avatar
openssl  
cRTrn13 committed
355

npzacs's avatar
npzacs committed
356
            // Read number of keys
cRTrn13's avatar
cRTrn13 committed
357
            file_seek(fp, f_pos, SEEK_SET);
npzacs's avatar
npzacs committed
358 359 360 361 362 363 364 365 366 367
            if ((file_read(fp, buf, 2)) == 2) {
                aacs->num_uks = MKINT_BE16(buf);

                X_FREE(aacs->uks);
                aacs->uks = calloc(aacs->num_uks, 16);

                DEBUG(DBG_AACS, "%d CPS unit keys\n", aacs->num_uks);

            } else {
                aacs->num_uks = 0;
npzacs's avatar
npzacs committed
368
                DEBUG(DBG_AACS | DBG_CRIT, "Error reading number of unit keys\n");
npzacs's avatar
npzacs committed
369
                error_code = AACS_ERROR_CORRUPTED_DISC;
npzacs's avatar
npzacs committed
370 371 372 373 374 375 376 377
            }

            // Read keys
            for (i = 0; i < aacs->num_uks; i++) {
                f_pos += 48;

                file_seek(fp, f_pos, SEEK_SET);
                if ((file_read(fp, buf, 16)) != 16) {
npzacs's avatar
npzacs committed
378
                    DEBUG(DBG_AACS, "Unit key %d: read error\n", i);
npzacs's avatar
npzacs committed
379
                    aacs->num_uks = i;
npzacs's avatar
npzacs committed
380
                    error_code = AACS_ERROR_CORRUPTED_DISC;
npzacs's avatar
npzacs committed
381 382
                    break;
                }
cRTrn13's avatar
openssl  
cRTrn13 committed
383

384 385 386 387 388 389
                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
390

391
                char str[40];
gates's avatar
gates committed
392
                DEBUG(DBG_AACS, "Unit key %d: %s\n", i,
393
                      print_hex(str, aacs->uks + 16*i, 16));
npzacs's avatar
npzacs committed
394
            }
cRTrn13's avatar
openssl  
cRTrn13 committed
395

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

npzacs's avatar
npzacs committed
399
            file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
400

npzacs's avatar
npzacs committed
401
            return error_code;
402 403 404
        }

        file_close(fp);
cRTrn13's avatar
openssl  
cRTrn13 committed
405

npzacs's avatar
npzacs committed
406
        DEBUG(DBG_AACS | DBG_CRIT, "Error reading unit keys\n");
npzacs's avatar
npzacs committed
407
        return AACS_ERROR_CORRUPTED_DISC;
cRTrn13's avatar
openssl  
cRTrn13 committed
408 409
}

410 411
static int _calc_title_hash(const char *path, uint8_t *title_hash)
{
412
    AACS_FILE_H *fp = NULL;
413 414 415
    uint8_t *ukf_buf;
    char     str[48];
    int64_t  f_size;
npzacs's avatar
npzacs committed
416
    int      result = AACS_SUCCESS;
417

npzacs's avatar
npzacs committed
418 419 420
    fp = _open_unit_key_file(path);
    if (!fp) {
        return AACS_ERROR_CORRUPTED_DISC;
421 422 423 424 425 426 427 428
    }

    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
429 430 431
    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
432

npzacs's avatar
npzacs committed
433 434 435
    } 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);
436 437 438 439 440
    }

    file_close(fp);
    X_FREE(ukf_buf);

npzacs's avatar
npzacs committed
441
    return result;
442
}
cRTrn13's avatar
cRTrn13 committed
443

npzacs's avatar
npzacs committed
444
static int _verify_ts(uint8_t *buf, size_t size)
445
{
446 447
    uint8_t *ptr;

cRTrn13's avatar
cRTrn13 committed
448 449 450 451 452 453 454
    if (size < 192) {
        return 1;
    }

    for (ptr=buf; ptr < buf+192; ptr++) {
        int failed = 0;
        if (*ptr == 0x47) {
455 456 457 458
            uint8_t *ptr2;

            for (ptr2=ptr; ptr2 < buf + size; ptr2 += 192) {
                if (*ptr2 != 0x47) {
cRTrn13's avatar
cRTrn13 committed
459 460
                    failed = 1;
                    break;
461 462
                }
            }
cRTrn13's avatar
cRTrn13 committed
463 464 465
            if (!failed) {
                return 1;
            }
466 467 468 469
        }
        ptr++;
    }

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

cRTrn13's avatar
cRTrn13 committed
472
    return 0;
473 474
}

475
/* Function that collects keys from keydb config entry */
476
static void _find_config_entry(AACS *aacs)
477
{
npzacs's avatar
npzacs committed
478
    uint8_t discid[20];
479
    char str[48];
npzacs's avatar
npzacs committed
480

481 482
    aacs->uks = NULL;
    aacs->num_uks = 0;
cRTrn13's avatar
cRTrn13 committed
483

npzacs's avatar
npzacs committed
484
    if (aacs->cf && aacs->cf->list) {
485 486 487 488 489
        aacs->ce = aacs->cf->list;
        while (aacs->ce && aacs->ce->entry.discid) {
            memset(discid, 0, sizeof(discid));
            hexstring_to_hex_array(discid, sizeof(discid),
                                   aacs->ce->entry.discid);
npzacs's avatar
npzacs committed
490
            if (!memcmp(aacs->disc_id, discid, 20)) {
491 492 493
                DEBUG(DBG_AACS, "Found config entry for discid %s\n",
                      aacs->ce->entry.discid);
                break;
494 495
            }

496
            aacs->ce = aacs->ce->next;
497
        }
498

499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
        if (aacs->ce->entry.mek) {
            hexstring_to_hex_array(aacs->mk, sizeof(aacs->mk),
                                    aacs->ce->entry.mek);

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

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

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

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
        if (aacs->ce->entry.vuk) {
            hexstring_to_hex_array(aacs->vuk, sizeof(aacs->vuk),
                                    aacs->ce->entry.vuk);

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

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

            digit_key_pair_list *ukcursor = aacs->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);

                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;
            }
        }
542
    }
543 544
}

545
#define ALIGNED_UNIT_LEN 6144
546
static int _decrypt_unit(AACS *aacs, uint8_t *out_buf, const uint8_t *in_buf, uint32_t curr_uk)
cRTrn13's avatar
cRTrn13 committed
547
{
548 549 550 551 552 553 554
    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);
555
    gcry_cipher_encrypt(gcry_h, key, 16, in_buf, 16);
556
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
557

cRTrn13's avatar
cRTrn13 committed
558
    for (a = 0; a < 16; a++) {
559
        key[a] ^= in_buf[a];
cRTrn13's avatar
cRTrn13 committed
560 561
    }

562 563
    memcpy(out_buf, in_buf, 16); /* first 16 bytes are plain */

564 565 566
    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);
567
    gcry_cipher_decrypt(gcry_h, out_buf + 16, ALIGNED_UNIT_LEN - 16, in_buf + 16, ALIGNED_UNIT_LEN - 16);
568
    gcry_cipher_close(gcry_h);
cRTrn13's avatar
cRTrn13 committed
569

570
    if (_verify_ts(out_buf, ALIGNED_UNIT_LEN)) {
cRTrn13's avatar
cRTrn13 committed
571 572 573
        return 1;
    }

574
    if (curr_uk < aacs->num_uks - 1) {
575
        return _decrypt_unit(aacs, out_buf, in_buf, curr_uk++);
npzacs's avatar
npzacs committed
576 577
    }

cRTrn13's avatar
cRTrn13 committed
578 579 580
    return 0;
}

npzacs's avatar
npzacs committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
static int _load_config(AACS *aacs, const char *configfile_path)
{
    int config_ok = 0;

    aacs->cf = keydbcfg_new_config_file();

    /* try to load KEYDB.cfg */

    if (configfile_path) {
        config_ok = keydbcfg_parse_config(aacs->cf, configfile_path);

    } else {
        /* If no configfile path given, check for config files in user's home or
         * under /etc.
         */
        char *cfgfile = keydbcfg_find_config_file();
        config_ok = keydbcfg_parse_config(aacs->cf, cfgfile);
        X_FREE(cfgfile);
    }

    /* Try to load simple (aacskeys) config files */

    config_ok = keydbcfg_load_pk_file(aacs->cf)   || config_ok;
    config_ok = keydbcfg_load_cert_file(aacs->cf) || config_ok;

    if (!config_ok) {
npzacs's avatar
npzacs committed
607
        DEBUG(DBG_AACS | DBG_CRIT, "No valid AACS configuration files found\n");
npzacs's avatar
npzacs committed
608
        return AACS_ERROR_NO_CONFIG;
npzacs's avatar
npzacs committed
609 610
    }

npzacs's avatar
npzacs committed
611
    return AACS_SUCCESS;
npzacs's avatar
npzacs committed
612 613
}

npzacs's avatar
npzacs committed
614 615
void aacs_get_version(int *major, int *minor, int *micro)
{
npzacs's avatar
npzacs committed
616 617 618
    *major = AACS_VERSION_MAJOR;
    *minor = AACS_VERSION_MINOR;
    *micro = AACS_VERSION_MICRO;
npzacs's avatar
npzacs committed
619 620
}

npzacs's avatar
npzacs committed
621
/* aacs_open2() wrapper for backwards compability */
cRTrn13's avatar
cRTrn13 committed
622
AACS *aacs_open(const char *path, const char *configfile_path)
npzacs's avatar
npzacs committed
623 624 625 626 627 628 629 630 631 632 633 634 635 636
{
    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
637
{
npzacs's avatar
npzacs committed
638
    DEBUG(DBG_AACS, "libaacs [%zd]\n", sizeof(AACS));
cRTrn13's avatar
cRTrn13 committed
639

640
    DEBUG(DBG_AACS, "Initializing libgcrypt...\n");
npzacs's avatar
npzacs committed
641
    if (!crypto_init()) {
npzacs's avatar
npzacs committed
642
        DEBUG(DBG_AACS | DBG_CRIT, "Failed to initialize libgcrypt\n");
643 644
        return NULL;
    }
645

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

npzacs's avatar
npzacs committed
648 649
    *error_code = _load_config(aacs, configfile_path);
    if (*error_code != AACS_SUCCESS) {
650 651 652 653
        aacs_close(aacs);
        return NULL;
    }

npzacs's avatar
npzacs committed
654 655 656 657 658
    *error_code = _calc_title_hash(path, aacs->disc_id);
    if (*error_code != AACS_SUCCESS) {
        aacs_close(aacs);
        return NULL;
    }
npzacs's avatar
npzacs committed
659

npzacs's avatar
npzacs committed
660 661
    DEBUG(DBG_AACS, "Searching for keydb config entry...\n");
    _find_config_entry(aacs);
662

npzacs's avatar
npzacs committed
663 664
    DEBUG(DBG_AACS, "Starting AACS waterfall...\n");
    *error_code = _calc_uks(aacs, path);
cRTrn13's avatar
cRTrn13 committed
665

npzacs's avatar
npzacs committed
666 667
    keydbcfg_config_file_close(aacs->cf);
    aacs->cf = NULL;
cRTrn13's avatar
cRTrn13 committed
668

npzacs's avatar
npzacs committed
669 670 671 672 673
    if (*error_code == AACS_SUCCESS) {
        DEBUG(DBG_AACS, "AACS initialized! (%p)\n", aacs);
    } else {
        DEBUG(DBG_AACS, "Failed to initialize AACS! (%p)\n", aacs);
    }
674

npzacs's avatar
npzacs committed
675
    return aacs;
cRTrn13's avatar
cRTrn13 committed
676 677
}

cRTrn13's avatar
cRTrn13 committed
678
void aacs_close(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
679
{
npzacs's avatar
npzacs committed
680 681 682
    if (!aacs)
        return;

683
    X_FREE(aacs->uks);
684
    X_FREE(aacs->cps_units);
685

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

cRTrn13's avatar
cRTrn13 committed
688 689 690
    X_FREE(aacs);
}

691
int aacs_decrypt_unit(AACS *aacs, uint8_t *buf)
692
{
693 694
    uint8_t out_buf[ALIGNED_UNIT_LEN];

695 696 697 698 699
    if (!(buf[0] & 0xc0)) {
        // TP_extra_header Copy_permission_indicator == 0, unit is not encrypted
        return 1;
    }

700
    if (_decrypt_unit(aacs, out_buf, buf, aacs->current_cps_unit)) {
701
        memcpy(buf, out_buf, ALIGNED_UNIT_LEN);
702 703 704 705 706 707 708

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

709 710 711
        return 1;
    }

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

714
    return 0;
715
}
cRTrn13's avatar
cRTrn13 committed
716

npzacs's avatar
npzacs committed
717 718 719 720 721
const uint8_t *aacs_get_disc_id(AACS *aacs)
{
    return aacs->disc_id;
}

722
const uint8_t *aacs_get_vid(AACS *aacs)
cRTrn13's avatar
cRTrn13 committed
723 724 725
{
    return aacs->vid;
}
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752

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);
}