libaacs | branch: master | Janusz Dziemidowicz <[email protected]> | Fri Sep 13 15:19:15 2013 +0200| [9ad1cd75b70e2b4a73417e5891848d3ff5891354] | committer: npzacs
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. > http://git.videolan.org/gitweb.cgi/libaacs.git/?a=commit;h=9ad1cd75b70e2b4a73417e5891848d3ff5891354 --- src/libaacs/aacs.c | 58 +++++++++++++++++++++++++++++++++++++++++++++------ src/libaacs/mmc.c | 59 ++++++++++++++++++++++++++++++++++++++-------------- src/libaacs/mmc.h | 4 +++- 3 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/libaacs/aacs.c b/src/libaacs/aacs.c index e90b616..ae5d306 100644 --- a/src/libaacs/aacs.c +++ b/src/libaacs/aacs.c @@ -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); } diff --git a/src/libaacs/mmc.c b/src/libaacs/mmc.c index 03f3e64..e3dc48d 100644 --- a/src/libaacs/mmc.c +++ b/src/libaacs/mmc.c @@ -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); diff --git a/src/libaacs/mmc.h b/src/libaacs/mmc.h index 2bae638..73fb022 100644 --- a/src/libaacs/mmc.h +++ b/src/libaacs/mmc.h @@ -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); _______________________________________________ libaacs-devel mailing list [email protected] https://mailman.videolan.org/listinfo/libaacs-devel
