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

Reply via email to