mmc.c 16.9 KB
Newer Older
1
2
/*
 * This file is part of libaacs
3
 * Copyright (C) 2009-2010  Obliter0n
4
 * Copyright (C) 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
 */

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

25
26
#include "mmc.h"
#include "crypto.h"
27
28
#include "util/macro.h"
#include "util/logging.h"
29

Accident's avatar
   
Accident committed
30
#include <stdlib.h>
gates's avatar
gates committed
31
#include <errno.h>
32
33
34
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
35

gates's avatar
gates committed
36
37
38
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
39

40
41
42
43
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif

44
#ifdef HAVE_LINUX_CDROM_H
45
#include <sys/ioctl.h>
46
#include <linux/cdrom.h>
cRTrn13's avatar
cRTrn13 committed
47
#endif
Accident's avatar
   
Accident committed
48

npzacs's avatar
npzacs committed
49
50
51
52
53
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
#endif

54
55
56
57
58
/* define in CFLAGS to skip drive certificate checks */
#ifndef PATCHED_DRIVE
#define PATCHED_DRIVE 0
#endif

npzacs's avatar
npzacs committed
59
60
61
62
#ifndef DEBUG_KEYS
#define DEBUG_KEYS 0
#endif

npzacs's avatar
npzacs committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#if defined(_WIN32)
/*
 * from ntddscsi.h, Windows DDK
 */
#   define SCSI_IOCTL_DATA_OUT             0
#   define SCSI_IOCTL_DATA_IN              1
#   define SCSI_IOCTL_DATA_UNSPECIFIED     2
#   define IOCTL_SCSI_PASS_THROUGH_DIRECT  0x4D014
#   define MAX_SENSE_LEN                   18

typedef struct _SCSI_PASS_THROUGH_DIRECT {
    USHORT Length;
    UCHAR  ScsiStatus;
    UCHAR  PathId;
    UCHAR  TargetId;
    UCHAR  Lun;
    UCHAR  CdbLength;
    UCHAR  SenseInfoLength;
    UCHAR  DataIn;
    ULONG  DataTransferLength;
    ULONG  TimeOutValue;
    PVOID  DataBuffer;
    ULONG  SenseInfoOffset;
    UCHAR  Cdb[16];
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;

#endif // defined(_WIN32)


npzacs's avatar
npzacs committed
92
struct mmc {
npzacs's avatar
npzacs committed
93
94
95
96
97
#if defined(_WIN32)
    HANDLE fd;
#else
    int    fd;
#endif
npzacs's avatar
npzacs committed
98
    uint8_t host_nonce[20];
99
    uint8_t host_key[20];
npzacs's avatar
npzacs committed
100
101
102
    uint8_t host_key_point[40];
};

gates's avatar
gates committed
103
104
static int _mmc_send_cmd(MMC *mmc, const uint8_t *cmd, uint8_t *buf, size_t tx,
                         size_t rx)
105
{
npzacs's avatar
npzacs committed
106
#if defined(HAVE_LINUX_CDROM_H)
npzacs's avatar
npzacs committed
107
    if (mmc->fd >= 0) {
108
109
110
111
112
113
        struct cdrom_generic_command cgc;
        struct request_sense sense;

        memset(&cgc, 0, sizeof(cgc));
        memcpy(cgc.cmd, cmd, CDROM_PACKET_SIZE);
        cgc.sense = &sense;
cRTrn13's avatar
cRTrn13 committed
114
        cgc.timeout = 5000;
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

        if (buf) {
            if (tx) {
                cgc.data_direction = CGC_DATA_WRITE;
                cgc.buflen = tx;
                cgc.buffer = buf;
            } else if (rx) {
                cgc.data_direction = CGC_DATA_READ;
                cgc.buflen = rx;
                cgc.buffer = buf;
            }
        } else {
            cgc.data_direction = CGC_DATA_NONE;
            cgc.buflen = 0;
            cgc.buffer = NULL;
        }
131

132
        int a = ioctl(mmc->fd, CDROM_SEND_PACKET, &cgc);
133

134
        char str[512];
gates's avatar
gates committed
135
        DEBUG(DBG_MMC, "Send LINUX MMC cmd %s: (%p)\n",
136
              print_hex(str, cmd, 16), mmc);
137
        if (tx) {
138
            DEBUG(DBG_MMC, "  Buffer: %s -> (%p)\n", print_hex(str, buf, tx), mmc);
139
        } else {
140
            DEBUG(DBG_MMC, "  Buffer: %s <- (%p)\n", print_hex(str, buf, rx), mmc);
141
142
        }

npzacs's avatar
npzacs committed
143
        if (a >= 0) {
npzacs's avatar
npzacs committed
144
            DEBUG(DBG_MMC, "  Send succeeded! [%d] (%p)\n", a, mmc);
145
146
            return 1;
        }
npzacs's avatar
npzacs committed
147

gates's avatar
gates committed
148
149
        DEBUG(DBG_MMC, "  Send failed! [%d] %s (%p)\n", a, strerror(errno),
              mmc);
150
    }
npzacs's avatar
npzacs committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194

#elif defined(_WIN32)

    DWORD dwBytesReturned;

    struct {
        SCSI_PASS_THROUGH_DIRECT sptd;
        UCHAR                    SenseBuf[MAX_SENSE_LEN];
    } sptd_sb;

    if (mmc->fd == INVALID_HANDLE_VALUE) {
        return 0;
    }

    sptd_sb.sptd.Length          = sizeof(SCSI_PASS_THROUGH_DIRECT);
    sptd_sb.sptd.PathId          = 0;
    sptd_sb.sptd.TargetId        = 0;
    sptd_sb.sptd.Lun             = 0;
    sptd_sb.sptd.CdbLength       = 12;
    sptd_sb.sptd.SenseInfoLength = MAX_SENSE_LEN;
    sptd_sb.sptd.TimeOutValue    = 5;
    sptd_sb.sptd.SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT);

    if (buf) {
        if (tx) {
            sptd_sb.sptd.DataIn = SCSI_IOCTL_DATA_OUT;
            sptd_sb.sptd.DataTransferLength = tx;
            sptd_sb.sptd.DataBuffer = buf;
        } else if (rx) {
            sptd_sb.sptd.DataIn = SCSI_IOCTL_DATA_IN;
            sptd_sb.sptd.DataTransferLength = rx;
            sptd_sb.sptd.DataBuffer = buf;
        }
    } else {
        sptd_sb.sptd.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
        sptd_sb.sptd.DataTransferLength = 0;
        sptd_sb.sptd.DataBuffer = NULL;
    }

    memcpy(sptd_sb.sptd.Cdb, cmd, 16);

    ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN);

    if (DeviceIoControl(mmc->fd,
npzacs's avatar
npzacs committed
195
                        IOCTL_SCSI_PASS_THROUGH_DIRECT,
npzacs's avatar
npzacs committed
196
197
198
199
200
201
202
203
204
205
206
207
                        (void*)&sptd_sb, sizeof(sptd_sb),
                        (void*)&sptd_sb, sizeof(sptd_sb),
                        &dwBytesReturned, NULL)) {

        if (sptd_sb.sptd.ScsiStatus == 0 /* STATUS_GOOD */) {
            DEBUG(DBG_MMC, "  Send succeeded! (%p)\n", mmc);
            return 1;
        }
    }

    DEBUG(DBG_MMC, "  Send failed! (%p)\n", mmc);

cRTrn13's avatar
cRTrn13 committed
208
#endif
209

210
    return 0;
211
212
}

gates's avatar
gates committed
213
214
215
static int _mmc_report_key(MMC *mmc, uint8_t agid, uint32_t addr,
                           uint8_t blocks, uint8_t format, uint8_t *buf,
                           uint16_t len)
216
217
{
    uint8_t cmd[16];
218
    memset(cmd, 0, sizeof(cmd));
219
220
    memset(buf, 0, len);

npzacs's avatar
npzacs committed
221
    DEBUG(DBG_MMC, "MMC report key... (%p)\n", mmc);
222

223
224
225
226
227
228
229
230
231
    cmd[0] = 0xa4;
    cmd[2] = (addr >> 24) & 0xff;
    cmd[3] = (addr >> 16) & 0xff;
    cmd[4] = (addr >> 8) & 0xff;
    cmd[5] = addr & 0xff;
    cmd[6] = blocks;
    cmd[7] = 0x02;
    cmd[8] = (len >> 8) & 0xff;
    cmd[9] = len & 0xff;
npzacs's avatar
npzacs committed
232
    cmd[10] = (agid << 6) | (format & 0x3f);
233

npzacs's avatar
npzacs committed
234
    return _mmc_send_cmd(mmc, cmd, buf, 0, len);
235
236
}

gates's avatar
gates committed
237
238
static int _mmc_send_key(MMC *mmc, uint8_t agid, uint8_t format, uint8_t *buf,
                         uint16_t len)
239
240
{
    uint8_t cmd[16];
241
    char str[512];
242
    memset(cmd, 0, sizeof(cmd));
243

244
    DEBUG(DBG_MMC, "MMC send key [%d] %s... (%p)\n", len, print_hex(str, buf, len),
gates's avatar
gates committed
245
          mmc);
246

247
248
249
250
    cmd[0] = 0xa3;
    cmd[7] = 0x02;
    cmd[8] = (len >> 8) & 0xff;
    cmd[9] = len & 0xff;
npzacs's avatar
npzacs committed
251
    cmd[10] = (agid << 6) | (format & 0x3f);
252

253
    DEBUG(DBG_MMC, "cmd: %s (%p)\n", print_hex(str, cmd, 16), mmc);
npzacs's avatar
npzacs committed
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
    return _mmc_send_cmd(mmc, cmd, buf, len, 0);
}

static int _mmc_invalidate_agid(MMC *mmc, uint8_t agid)
{
    uint8_t buf[2];
    memset(buf, 0, sizeof(buf));

    return _mmc_report_key(mmc, agid, 0, 0, 0x3f, buf, 2);
}

static void _mmc_invalidate_agids(MMC *mmc)
{
    int     agid;

    /* invalidate all agids */
    for (agid = 0; agid < 4; agid++) {
        _mmc_invalidate_agid(mmc, agid);
    }
}

static int _mmc_report_agid(MMC *mmc, uint8_t *agid)
{
    uint8_t buf[8];
    memset(buf, 0, sizeof(buf));

    int result = _mmc_report_key(mmc, 0, 0, 0, 0, buf, 8);
    if (result) {
        *agid = (buf[7] & 0xff) >> 6;
    }
    return result;
285
286
}

gates's avatar
gates committed
287
288
289
static int _mmc_send_host_cert(MMC *mmc, uint8_t agid,
                               const uint8_t *host_nonce,
                               const uint8_t *host_cert)
290
291
292
293
294
295
296
297
298
299
300
{
    uint8_t buf[116];
    memset(buf, 0, sizeof(buf));

    buf[1] = 0x72;
    memcpy(buf + 4,  host_nonce, 20);
    memcpy(buf + 24, host_cert,  92);

    return _mmc_send_key(mmc, agid, 0x01, buf, 116);
}

gates's avatar
gates committed
301
302
static int _mmc_read_drive_cert(MMC *mmc, uint8_t agid, uint8_t *drive_nonce,
                                uint8_t *drive_cert)
303
304
305
306
307
308
309
310
311
312
313
314
{
    uint8_t buf[116];
    memset(buf, 0, sizeof(buf));

    if (_mmc_report_key(mmc, agid, 0, 0, 0x01, buf, 116)) {
        memcpy(drive_nonce, buf + 4,  20);
        memcpy(drive_cert,  buf + 24, 92);
        return 1;
    }
    return 0;
}

gates's avatar
gates committed
315
316
static int _mmc_read_drive_key(MMC *mmc, uint8_t agid, uint8_t *drive_key_point,
                               uint8_t *drive_key_signature)
317
318
319
320
321
322
323
324
325
326
327
328
{
    uint8_t buf[84];
    memset(buf, 0, sizeof(buf));

    if (_mmc_report_key(mmc, agid, 0, 0, 0x02, buf, 84)) {
        memcpy(drive_key_point,     buf + 4,  40);
        memcpy(drive_key_signature, buf + 44, 40);
        return 1;
    }
    return 0;
}

gates's avatar
gates committed
329
330
331
static int _mmc_send_host_key(MMC *mmc, uint8_t agid,
                              const uint8_t *host_key_point,
                              const uint8_t *host_key_signature)
332
333
{
    uint8_t buf[84];
334
    memset(buf, 0, sizeof(buf));
335
336
337
338
339
340
341
342

    buf[1] = 0x52;
    memcpy(buf + 4,  host_key_point,     40);
    memcpy(buf + 44, host_key_signature, 40);

    return _mmc_send_key(mmc, agid, 0x02, buf, 84);
}

gates's avatar
gates committed
343
344
static int _mmc_read_vid(MMC *mmc, uint8_t agid, uint8_t *volume_id,
                         uint8_t *mac)
345
346
347
{
    uint8_t buf[36];
    uint8_t cmd[16];
348
    memset(cmd, 0, sizeof(cmd));
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
    memset(buf, 0, 36);

    cmd[0] = 0xad;
    cmd[1] = 1;    // 1 = BLURAY
    cmd[7] = 0x80;
    cmd[9] = 0x24;
    cmd[10] = (agid << 6) & 0xc0;

    if (_mmc_send_cmd(mmc, cmd, buf, 0, 36)) {
        memcpy(volume_id, buf + 4,  16);
        memcpy(mac,       buf + 20, 16);
        return 1;
    }

    return 0;
}

npzacs's avatar
npzacs committed
366
MMC *mmc_open(const char *path)
367
{
npzacs's avatar
npzacs committed
368
    MMC *mmc = calloc(1, sizeof(MMC));
npzacs's avatar
npzacs committed
369

npzacs's avatar
npzacs committed
370
    crypto_create_nonce(mmc->host_nonce, sizeof(mmc->host_nonce));
371

npzacs's avatar
npzacs committed
372
    if (DEBUG_KEYS) {
373
374
375
376
377
        char str[sizeof(mmc->host_nonce)*2 + 1];
        DEBUG(DBG_MMC, "Created host nonce (Hn): %s\n",
              print_hex(str, mmc->host_nonce, sizeof(mmc->host_nonce)));
    }

npzacs's avatar
npzacs committed
378
    crypto_create_host_key_pair(mmc->host_key, mmc->host_key_point);
379

npzacs's avatar
npzacs committed
380
    if (DEBUG_KEYS) {
381
382
383
384
385
386
387
        char    str[sizeof(mmc->host_key_point)*2 + 1];
        DEBUG(DBG_MMC, "Created host key (Hk): %s\n",
              print_hex(str, mmc->host_key, sizeof(mmc->host_key)));
        DEBUG(DBG_MMC, "Created host key point (Hv): %s\n",
              print_hex(str, mmc->host_key_point, sizeof(mmc->host_key_point)));
    }

npzacs's avatar
npzacs committed
388
#if defined(HAVE_MNTENT_H)
389

npzacs's avatar
npzacs committed
390
#ifdef HAVE_REALPATH
391
392
393
394
395
396
397
    char *file_path = malloc(PATH_MAX);
    if (!file_path || !realpath(path, file_path)) {
        DEBUG(DBG_MMC, "Failed resolving path %s (%p)\n", path, mmc);
        X_FREE(mmc);
        X_FREE(file_path);
        return NULL;
    }
npzacs's avatar
npzacs committed
398
#else
399
400
    char *file_path = (char*)malloc(strlen(path) + 1);
    strcpy(file_path, path);
npzacs's avatar
npzacs committed
401
402
#endif

403
404
405
    int   path_len  = strlen(file_path);
    FILE *proc_mounts;

npzacs's avatar
npzacs committed
406
    mmc->fd = -1;
npzacs's avatar
npzacs committed
407
408

    // strip trailing '/'s
409
410
    while (path_len > 0 && file_path[--path_len] == '/') {
        file_path[path_len] = '\0';
npzacs's avatar
npzacs committed
411
    }
412

npzacs's avatar
npzacs committed
413
    DEBUG(DBG_MMC, "Opening LINUX MMC drive %s... (%p)\n", file_path, mmc);
414

415
416
417
418
    if ((proc_mounts = setmntent("/proc/mounts", "r"))) {
        struct mntent* mount_entry;

        while ((mount_entry = getmntent(proc_mounts)) != NULL) {
419
            if (strcmp(mount_entry->mnt_dir, file_path) == 0) {
npzacs's avatar
npzacs committed
420
421
                mmc->fd = open(mount_entry->mnt_fsname, O_RDONLY | O_NONBLOCK);
                if (mmc->fd >= 0) {
npzacs's avatar
npzacs committed
422
423
                    DEBUG(DBG_MMC, "LINUX MMC drive %s opened - fd: %d (%p)\n",
                          mount_entry->mnt_fsname, mmc->fd, mmc);
npzacs's avatar
npzacs committed
424
                    break;
npzacs's avatar
npzacs committed
425
                }
npzacs's avatar
npzacs committed
426

npzacs's avatar
npzacs committed
427
428
                DEBUG(DBG_MMC, "Failed opening LINUX MMC drive %s mounted to %s (%p)\n",
                      mount_entry->mnt_fsname, file_path, mmc);
npzacs's avatar
npzacs committed
429
            }
430
431
432
        }

        endmntent(proc_mounts);
npzacs's avatar
npzacs committed
433
434
    } else {
        DEBUG(DBG_MMC, "Error opening /proc/mounts (%p)\n", mmc);
435
436
    }

npzacs's avatar
npzacs committed
437
    if (mmc->fd < 0) {
npzacs's avatar
npzacs committed
438
        DEBUG(DBG_MMC, "Error opening LINUX MMC drive mounted to %s (%p)\n", file_path, mmc);
npzacs's avatar
npzacs committed
439
440
441
        X_FREE(mmc);
    }

npzacs's avatar
npzacs committed
442
443
    X_FREE(file_path);

npzacs's avatar
npzacs committed
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
#elif defined(_WIN32)
    char drive[] = { path[0], ':', '\\', 0 };
    char volume[] = {'\\', '\\', '.', '\\', path[0], ':', 0};

    DEBUG(DBG_MMC, "Opening Windows MMC drive %s... (%p)\n", drive, mmc);

    UINT type = GetDriveType(drive);

    if (type != DRIVE_CDROM) {
        DEBUG(DBG_MMC, "Drive %s is not CD/DVD drive !\n", drive);
        X_FREE(mmc);
        return NULL;
    }

    mmc->fd = CreateFile(volume, GENERIC_READ | GENERIC_WRITE,
                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (mmc->fd == INVALID_HANDLE_VALUE) {
        mmc->fd = CreateFile(volume, GENERIC_READ,
                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (mmc->fd == INVALID_HANDLE_VALUE) {
            DEBUG(DBG_MMC, "Failed opening Windows MMC drive %s (%p)\n", volume, mmc);
            X_FREE(mmc);
            return NULL;
        }
    }

    DEBUG(DBG_MMC, "Windows MMC drive %s opened (%p)\n", volume, mmc);

474
475
476
477
478
#else

    DEBUG(DBG_MMC, "No MMC drive support !\n");
    X_FREE(mmc);

cRTrn13's avatar
cRTrn13 committed
479
#endif
cRTrn13's avatar
cRTrn13 committed
480

481
    return mmc;
482
483
484
485
}

void mmc_close(MMC *mmc)
{
npzacs's avatar
npzacs committed
486
    if (mmc) {
487

npzacs's avatar
npzacs committed
488
#if defined(HAVE_LINUX_CDROM_H)
npzacs's avatar
npzacs committed
489
490
491
        if (mmc->fd >= 0) {
            close(mmc->fd);
        }
492

npzacs's avatar
npzacs committed
493
494
495
496
497
498
#elif defined(_WIN32)
        if (mmc->fd != INVALID_HANDLE_VALUE) {
            CloseHandle(mmc->fd);
        }
#endif

npzacs's avatar
npzacs committed
499
500
501
502
        DEBUG(DBG_MMC, "Closed MMC drive (%p)\n", mmc);

        X_FREE(mmc);
    }
503
504
}

505
506
507
508
509
510
511
512
513
514
515
static int _verify_signature(const uint8_t *cert, const uint8_t *signature,
                             const uint8_t *nonce, const uint8_t *point)
{
    uint8_t data[60];

    memcpy(data,      nonce, 20);
    memcpy(data + 20, point, 40);

    return crypto_aacs_verify(cert, signature, data, 60);
}

npzacs's avatar
npzacs committed
516
int mmc_read_vid(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cert, uint8_t *vid)
517
{
518
    uint8_t agid = 0, hks[40], dn[20], dc[92], dkp[40], dks[40], mac[16];
519
    char str[512];
npzacs's avatar
npzacs committed
520
    int error_code = MMC_ERROR;
521

522
    memset(hks, 0, sizeof(hks));
523

npzacs's avatar
npzacs committed
524
    DEBUG(DBG_MMC, "Reading VID from drive... (%p)\n", mmc);
525

npzacs's avatar
npzacs committed
526
    _mmc_invalidate_agids(mmc);
527

npzacs's avatar
npzacs committed
528
    if (!_mmc_report_agid(mmc, &agid)) {
npzacs's avatar
npzacs committed
529
        DEBUG(DBG_MMC | DBG_CRIT, "Didn't get AGID from drive (%p)\n", mmc);
npzacs's avatar
npzacs committed
530
        return MMC_ERROR;
npzacs's avatar
npzacs committed
531
    }
npzacs's avatar
npzacs committed
532
    DEBUG(DBG_MMC, "Got AGID from drive: %d (%p)\n", agid, mmc);
533

534
    if (!PATCHED_DRIVE) do {
535

536
        if (DEBUG_KEYS) {
npzacs's avatar
npzacs committed
537
            DEBUG(DBG_MMC, "Host certificate   : %s (%p)\n", print_hex(str, host_cert,       92), mmc);
538
539
540
            DEBUG(DBG_MMC, "Host nonce         : %s (%p)\n", print_hex(str, mmc->host_nonce, 20), mmc);
        }

541
        // send host cert + nonce
npzacs's avatar
npzacs committed
542
        if (!_mmc_send_host_cert(mmc, agid, mmc->host_nonce, host_cert)) {
gates's avatar
gates committed
543
544
545
            DEBUG(DBG_MMC | DBG_CRIT,
                  "Host key / Certificate has been revoked by your drive ? "
                  "(%p)\n", mmc);
npzacs's avatar
npzacs committed
546
            error_code = MMC_ERROR_CERT_REVOKED;
547
548
            break;
        }
549

550
551
        // receive mmc cert + nonce
        if (!_mmc_read_drive_cert(mmc, agid, dn, dc)) {
gates's avatar
gates committed
552
553
            DEBUG(DBG_MMC | DBG_CRIT,
                  "Drive doesn't give its certificate (%p)\n", mmc);
554
555
            break;
        }
npzacs's avatar
npzacs committed
556
557
558
559
560

        if (DEBUG_KEYS) {
            DEBUG(DBG_MMC, "Drive certificate   : %s (%p)\n", print_hex(str, dc, 92), mmc);
            DEBUG(DBG_MMC, "Drive nonce         : %s (%p)\n", print_hex(str, dn, 20), mmc);
        }
561

562
563
564
565
566
567
        // verify drive certificate
        if (!crypto_aacs_verify_drive_cert(dc)) {
            DEBUG(DBG_MMC | DBG_CRIT, "Drive certificate is invalid (%p)\n", mmc);
            break;
        }

568
569
        // receive mmc key
        if (!_mmc_read_drive_key(mmc, agid, dkp, dks)) {
gates's avatar
gates committed
570
571
            DEBUG(DBG_MMC | DBG_CRIT, "Drive doesn't give its drive key (%p)\n",
                  mmc);
572
573
            break;
        }
npzacs's avatar
npzacs committed
574
575
576
577
578

        if (DEBUG_KEYS) {
            DEBUG(DBG_MMC, "Drive key point     : %s (%p)\n", print_hex(str, dkp, 40), mmc);
            DEBUG(DBG_MMC, "Drive key signature : %s (%p)\n", print_hex(str, dks, 40), mmc);
        }
579

580
581
582
583
584
585
586
        // verify drive signature
        if (!_verify_signature(dc, dks, mmc->host_nonce, dkp)) {
            DEBUG(DBG_MMC | DBG_CRIT, "Drive signature is invalid\n");
            break;
        }

        // sign
npzacs's avatar
npzacs committed
587
        crypto_aacs_sign(host_cert, host_priv_key, hks, dn,
gates's avatar
gates committed
588
                         mmc->host_key_point);
589

590
        // verify own signature
npzacs's avatar
npzacs committed
591
        if (!_verify_signature(host_cert, hks, dn, mmc->host_key_point)) {
592
593
594
595
            DEBUG(DBG_MMC | DBG_CRIT, "Created signature is invalid ?\n");
            break;
        }

596
597
        // send signed host key and point
        if (!_mmc_send_host_key(mmc, agid, mmc->host_key_point, hks)) {
gates's avatar
gates committed
598
599
600
            DEBUG(DBG_MMC | DBG_CRIT, "Error sending host signature (%p)\n",
                  mmc);
            DEBUG(DBG_MMC,  "Host key signature : %s (%p)\n",
601
                  print_hex(str, hks, 40), mmc);
602
603
604
605
            break;
        }

    } while (0);
606

607
    if (_mmc_read_vid(mmc, agid, vid, mac)) {
608
609
        DEBUG(DBG_MMC, "VID: %s (%p)\n", print_hex(str, vid, 16), mmc);
        DEBUG(DBG_MMC, "MAC: %s (%p)\n", print_hex(str, mac, 16), mmc);
cRTrn13's avatar
cRTrn13 committed
610

npzacs's avatar
npzacs committed
611
612
        _mmc_invalidate_agid(mmc, agid);

npzacs's avatar
npzacs committed
613
        return MMC_SUCCESS;
cRTrn13's avatar
cRTrn13 committed
614
615
    }

npzacs's avatar
npzacs committed
616
    DEBUG(DBG_MMC | DBG_CRIT, "Unable to read VID from drive! (%p)\n", mmc);
npzacs's avatar
npzacs committed
617
618

    _mmc_invalidate_agid(mmc, agid);
619

npzacs's avatar
npzacs committed
620
    return error_code;
621
}