Commit 9ad1cd75 authored by Janusz Dziemidowicz's avatar Janusz Dziemidowicz Committed by npzacs
Browse files

Fix reading PMSN

While working on bus encryption I've found out that some drives (if
not all) require a new AACS-Auth for reading data keys. It seems that
the same goes for reading PMSN. After digging through my discs I've
finally found one with PMSN and I was able to verify this with two LG
drives. Fix it by moving PMSN reading to a separate function with a
new AACS-Auth.
parent 393a5127
......@@ -269,10 +269,10 @@ static MKB *_get_hrl_mkb(MMC *mmc)
return mkb;
}
static int _read_vid(AACS *aacs, cert_list *hcl, int force_mmc)
static int _read_vid(AACS *aacs, cert_list *hcl)
{
/* Use VID given in config file if available */
if (!force_mmc && memcmp(aacs->vid, empty_key, 16)) {
if (memcmp(aacs->vid, empty_key, 16)) {
return AACS_SUCCESS;
}
......@@ -308,7 +308,7 @@ static int _read_vid(AACS *aacs, cert_list *hcl, int force_mmc)
DEBUG(DBG_AACS, "Trying host certificate (id 0x%s)...\n",
print_hex(tmp_str, cert + 4, 6));
int mmc_result = mmc_read_vid(mmc, priv_key, cert, aacs->vid, aacs->pmsn);
int mmc_result = mmc_read_vid(mmc, priv_key, cert, aacs->vid);
switch (mmc_result) {
case MMC_SUCCESS:
mkb_close(hrl_mkb);
......@@ -380,6 +380,52 @@ static int _read_read_data_key(AACS *aacs, cert_list *hcl)
return error_code;
}
static int _read_pmsn(AACS *aacs, cert_list *hcl)
{
MMC* mmc = NULL;
if (!(mmc = mmc_open(aacs->path))) {
return AACS_ERROR_MMC_OPEN;
}
int error_code = AACS_ERROR_NO_CERT;
for (;hcl && hcl->host_priv_key && hcl->host_cert; hcl = hcl->next) {
char tmp_str[2*92+1];
uint8_t priv_key[20], cert[92];
hexstring_to_hex_array(priv_key, sizeof(priv_key), hcl->host_priv_key);
hexstring_to_hex_array(cert, sizeof(cert), hcl->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));
continue;
}
DEBUG(DBG_AACS, "Trying host certificate (id 0x%s)...\n",
print_hex(tmp_str, cert + 4, 6));
int mmc_result = mmc_read_pmsn(mmc, priv_key, cert, aacs->pmsn);
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;
}
}
mmc_close(mmc);
DEBUG(DBG_AACS, "Error reading PMSN!\n");
return error_code;
}
static int _calc_vuk(AACS *aacs, uint8_t *mk, uint8_t *vuk,
pk_list *pkl, cert_list *host_cert_list)
{
......@@ -404,7 +450,7 @@ static int _calc_vuk(AACS *aacs, uint8_t *mk, uint8_t *vuk,
}
/* acquire VID */
error_code = _read_vid(aacs, host_cert_list, 0);
error_code = _read_vid(aacs, host_cert_list);
if (error_code != AACS_SUCCESS) {
return error_code;
}
......@@ -969,7 +1015,7 @@ const uint8_t *aacs_get_vid(AACS *aacs)
config_file *cf = keydbcfg_config_load(NULL);
if (cf) {
_read_vid(aacs, cf->host_cert_list, 0);
_read_vid(aacs, cf->host_cert_list);
keydbcfg_config_file_close(cf);
}
......@@ -988,7 +1034,7 @@ const uint8_t *aacs_get_pmsn(AACS *aacs)
if (!memcmp(aacs->pmsn, empty_key, 16)) {
config_file *cf = keydbcfg_config_load(NULL);
if (cf) {
_read_vid(aacs, cf->host_cert_list, 1);
_read_pmsn(aacs, cf->host_cert_list);
keydbcfg_config_file_close(cf);
}
......
......@@ -1102,7 +1102,7 @@ static int _mmc_aacs_auth(MMC *mmc, uint8_t agid, const uint8_t *host_priv_key,
return MMC_SUCCESS;
}
int mmc_read_vid(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cert, uint8_t *vid, uint8_t *pmsn)
int mmc_read_vid(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cert, uint8_t *vid)
{
uint8_t agid = 0, mac[16], calc_mac[16], bus_key[16];
char str[512];
......@@ -1135,22 +1135,49 @@ int mmc_read_vid(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cer
DEBUG(DBG_MMC | DBG_CRIT, "VID MAC is incorrect. This means this Volume ID is not correct.\n");
}
/* read pmsn */
if (_mmc_read_pmsn(mmc, agid, pmsn, mac)) {
if (DEBUG_KEYS) {
DEBUG(DBG_MMC, "PMSN : %s\n", print_hex(str, pmsn, 16));
DEBUG(DBG_MMC, "PMSN MAC : %s\n", print_hex(str, mac, 16));
}
_mmc_invalidate_agid(mmc, agid);
/* verify CMAC */
crypto_aes_cmac_16(vid, bus_key, calc_mac);
if (memcmp(calc_mac, mac, 16)) {
DEBUG(DBG_MMC | DBG_CRIT, "PMSN MAC is incorrect. This means PMSN is not correct.\n");
}
return MMC_SUCCESS;
}
} else {
memset(pmsn, 0, 16);
DEBUG(DBG_MMC, "Unable to read PMSN from drive!\n");
DEBUG(DBG_MMC | DBG_CRIT, "Unable to read VID from drive!\n");
_mmc_invalidate_agid(mmc, agid);
return MMC_ERROR;
}
int mmc_read_pmsn(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cert, uint8_t *pmsn)
{
uint8_t agid = 0, mac[16], calc_mac[16], bus_key[16];
char str[512];
int error_code;
DEBUG(DBG_MMC, "Reading PMSN from drive...\n");
_mmc_invalidate_agids(mmc);
if (!_mmc_report_agid(mmc, &agid)) {
DEBUG(DBG_MMC | DBG_CRIT, "Didn't get AGID from drive\n");
return MMC_ERROR;
}
DEBUG(DBG_MMC, "Got AGID from drive: %d\n", agid);
error_code = _mmc_aacs_auth(mmc, agid, host_priv_key, host_cert, bus_key);
if (error_code) {
return error_code;
}
if (_mmc_read_pmsn(mmc, agid, pmsn, mac)) {
if (DEBUG_KEYS) {
DEBUG(DBG_MMC, "PMSN : %s\n", print_hex(str, pmsn, 16));
DEBUG(DBG_MMC, "PMSN MAC : %s\n", print_hex(str, mac, 16));
}
/* verify MAC */
crypto_aes_cmac_16(pmsn, bus_key, calc_mac);
if (memcmp(calc_mac, mac, 16)) {
DEBUG(DBG_MMC | DBG_CRIT, "PMSN MAC is incorrect. This means this Pre-recorded Medial Serial Number is not correct.\n");
}
_mmc_invalidate_agid(mmc, agid);
......@@ -1158,7 +1185,7 @@ int mmc_read_vid(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cer
return MMC_SUCCESS;
}
DEBUG(DBG_MMC | DBG_CRIT, "Unable to read VID from drive!\n");
DEBUG(DBG_MMC | DBG_CRIT, "Unable to read PMSN from drive!\n");
_mmc_invalidate_agid(mmc, agid);
......
......@@ -34,7 +34,9 @@ typedef struct mmc MMC;
AACS_PRIVATE MMC *mmc_open(const char *path);
AACS_PRIVATE void mmc_close(MMC *mmc);
AACS_PRIVATE int mmc_read_vid(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cert,
uint8_t *vid, uint8_t *pmsn);
uint8_t *vid);
AACS_PRIVATE int mmc_read_pmsn(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cert,
uint8_t *pmsn);
AACS_PRIVATE int mmc_read_data_keys(MMC *mmc, const uint8_t *host_priv_key, const uint8_t *host_cert,
uint8_t *read_data_key, uint8_t *write_data_key);
AACS_PRIVATE int mmc_read_drive_cert(MMC *mmc, uint8_t *drive_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