Commit b56e1db8 authored by npzacs's avatar npzacs
Browse files

Verify content certificate signature

parent 10cb655c
- Verify content certificate signature.
- Fix build with gcrypt < 1.6.0.
2015-03-13: Version 0.8.1
......
......@@ -12,6 +12,8 @@ lib_LTLIBRARIES = libaacs.la
libaacs_la_SOURCES=\
src/libaacs/aacs.h \
src/libaacs/aacs.c \
src/libaacs/content_cert.h \
src/libaacs/content_cert.c \
src/libaacs/crypto.h \
src/libaacs/crypto.c \
src/libaacs/mkb.h \
......
......@@ -26,6 +26,7 @@
#include "aacs-version.h"
#include "aacs.h"
#include "content_cert.h"
#include "crypto.h"
#include "mmc.h"
#include "mkb.h"
......@@ -81,6 +82,9 @@ struct aacs {
int bec; /* bus encryption capable flag in drive certificate */
uint8_t read_data_key[16];
/* content certificate */
CONTENT_CERT *cc;
/* AACS Online (BD-J) */
uint8_t device_nonce[16];
uint8_t device_binding_id[16];
......@@ -843,27 +847,73 @@ static int _calc_title_hash(AACS *aacs)
return result;
}
static int _get_bus_encryption_enabled(AACS *aacs)
static size_t _read_file(AACS *aacs, const char *file, void **data)
{
AACS_FILE_H *fp = NULL;
uint8_t buf[2];
int bee = 0;
int64_t f_size;
*data = NULL;
fp = _file_open(aacs, "AACS" DIR_SEP "Content000.cer");
fp = _file_open(aacs, file);
if (!fp) {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Unable to open content certificate (AACS/Content000.cer)\n");
BD_DEBUG(DBG_AACS | DBG_CRIT, "Unable to open %s\n", file);
return 0;
}
if (file_read(fp, buf, 2) == 2) {
bee = (buf[1] & 0x80) >> 7;
BD_DEBUG(DBG_AACS, "Bus Encryption Enabled flag in content certificate: %d\n", bee);
file_seek(fp, 0, SEEK_END);
f_size = file_tell(fp);
file_seek(fp, 0, SEEK_SET);
*data = malloc(f_size);
if (*data) {
if (file_read(fp, *data, f_size) != f_size) {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Failed reading %s\n", file);
X_FREE(*data);
}
} else {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Failed to read Bus Encryption Enabled flag from content certificate file\n");
BD_DEBUG(DBG_AACS | DBG_CRIT, "Out of memory\n");
}
file_close(fp);
return bee;
return *data ? f_size : 0;
}
static CONTENT_CERT *_read_cc_any(AACS *aacs)
{
CONTENT_CERT *cc = NULL;
void *data;
size_t size;
size = _read_file(aacs, "AACS" DIR_SEP "Content000.cer", &data);
if (!size) {
size = _read_file(aacs, "AACS" DIR_SEP "Content001.cer", &data);
}
if (size) {
cc = cc_parse(data, size);
X_FREE(data);
} else {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Failed to read content certificate file\n");
}
return cc;
}
static int _get_bus_encryption_enabled(AACS *aacs)
{
if (!aacs->cc) {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Failed to read Bus Encryption Enabled flag from content certificate file\n");
return 0;
}
if (aacs->cc->bus_encryption_enabled_flag) {
BD_DEBUG(DBG_AACS, "Bus Encryption Enabled flag in content certificate: %d\n",
aacs->cc->bus_encryption_enabled_flag);
return 1;
}
return 0;
}
static int _get_bus_encryption_capable(const char *path)
......@@ -1023,6 +1073,8 @@ int aacs_open_device(AACS *aacs, const char *path, const char *configfile_path)
BD_DEBUG(DBG_AACS, "Failed to initialize AACS!\n");
}
aacs->cc = _read_cc_any(aacs);
aacs->bee = _get_bus_encryption_enabled(aacs);
aacs->bec = _get_bus_encryption_capable(path);
......@@ -1059,6 +1111,8 @@ void aacs_close(AACS *aacs)
X_FREE(aacs->cps_units);
X_FREE(aacs->path);
cc_free(&aacs->cc);
BD_DEBUG(DBG_AACS, "AACS destroyed!\n");
/* erase sensitive data */
......
/*
* This file is part of libaacs
* Copyright (C) 2015 npzacs
*
* 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.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* 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/>.
*/
#include "content_cert.h"
#include "crypto.h"
#include "util/logging.h"
#include "util/macro.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
CONTENT_CERT *cc_parse(const void *data, size_t len)
{
const uint8_t *p = data;
if (len < 87) {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Invalid content certificate (length %zd < 87)\n", len);
return NULL;
}
if (p[0] != 0) {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Invalid content certificate type 0x%02x\n", p[0]);
return NULL;
}
/* calculate certificate length */
size_t length_format_specific = MKINT_BE16(p + 24);
size_t num_digest = MKINT_BE16(p + 12);
size_t cert_data_len = 26 + length_format_specific + num_digest*8;
if (len < cert_data_len + 40) {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Invalid content certificate (length %zd < %zd)\n",
len, cert_data_len + 40);
return NULL;
}
/* check signature */
if (!crypto_aacs_verify_aacscc(p + cert_data_len, p, cert_data_len)) {
BD_DEBUG(DBG_AACS | DBG_CRIT, "Invalid content certificate signature\n");
return NULL;
}
/* return useful data */
CONTENT_CERT *c = calloc(1, sizeof(CONTENT_CERT));
c->bus_encryption_enabled_flag = p[1] >> 7;
return c;
}
void cc_free(CONTENT_CERT **pc)
{
if (pc && *pc) {
X_FREE(*pc);
}
}
/*
* This file is part of libaacs
* Copyright (C) 2015 npzacs
*
* 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.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* 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/>.
*/
#ifndef CONTENT_CERT_H_
#define CONTENT_CERT_H_
#include "util/attributes.h"
#include <stdlib.h>
#include <stdint.h>
typedef struct content_cert CONTENT_CERT;
struct content_cert {
uint8_t bus_encryption_enabled_flag;
};
BD_PRIVATE CONTENT_CERT *cc_parse(const void *data, size_t len);
BD_PRIVATE void cc_free(CONTENT_CERT **);
#endif /* CONTENT_CERT_H_ */
......@@ -539,6 +539,16 @@ int crypto_aacs_verify_aacsla(const uint8_t *signature, const uint8_t *data, ui
return !_aacs_verify(signature, aacs_la_pubkey_x, aacs_la_pubkey_y, data, len);
}
int crypto_aacs_verify_aacscc(const uint8_t *signature, const uint8_t *data, uint32_t len)
{
static const uint8_t aacs_cc_pubkey_x[] = { 0x78, 0x4C, 0xF5, 0xC3, 0x63, 0x97, 0xA4, 0x39, 0x04, 0x06,
0xA4, 0x9F, 0x78, 0x00, 0xC7, 0x7D, 0xE9, 0x0C, 0xB3, 0x4C };
static const uint8_t aacs_cc_pubkey_y[] = { 0x00, 0x1D, 0xF3, 0x6B, 0x8F, 0x2E, 0xCF, 0x83, 0xCD, 0xEE,
0x43, 0x8F, 0x7F, 0xD1, 0xF4, 0x80, 0x6F, 0xD2, 0x0D, 0xE7 };
return !_aacs_verify(signature, aacs_cc_pubkey_x, aacs_cc_pubkey_y, data, len);
}
int crypto_aacs_verify_cert(const uint8_t *cert)
{
if (MKINT_BE16(cert+2) != 0x5c) {
......
......@@ -38,6 +38,7 @@ BD_PRIVATE void crypto_aacs_title_hash(const uint8_t *ukf, uint64_t len, uint8_t
BD_PRIVATE int crypto_aacs_verify(const uint8_t *cert, const uint8_t *signature, const uint8_t *data, uint32_t len);
BD_PRIVATE int crypto_aacs_verify_aacsla(const uint8_t *signature, const uint8_t *data, uint32_t len);
BD_PRIVATE int crypto_aacs_verify_aacscc(const uint8_t *signature, const uint8_t *data, uint32_t len);
BD_PRIVATE int crypto_aacs_verify_cert(const uint8_t *cert);
BD_PRIVATE int crypto_aacs_verify_host_cert(const uint8_t *cert);
BD_PRIVATE int crypto_aacs_verify_drive_cert(const uint8_t *cert);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment