libaacs | branch: master | npzacs <npz...@gmail.com> | Sun Apr 26 18:51:26 2015 
+0300| [b56e1db8a146f81ddbf96675d9624bd846628353] | committer: npzacs

Verify content certificate signature

> http://git.videolan.org/gitweb.cgi/libaacs.git/?a=commit;h=b56e1db8a146f81ddbf96675d9624bd846628353
---

 ChangeLog                  |    1 +
 Makefile.am                |    2 ++
 src/libaacs/aacs.c         |   74 +++++++++++++++++++++++++++++++++++------
 src/libaacs/content_cert.c |   78 ++++++++++++++++++++++++++++++++++++++++++++
 src/libaacs/content_cert.h |   38 +++++++++++++++++++++
 src/libaacs/crypto.c       |   10 ++++++
 src/libaacs/crypto.h       |    1 +
 7 files changed, 194 insertions(+), 10 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 42a61d4..d5d7e18 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+- Verify content certificate signature.
 - Fix build with gcrypt < 1.6.0.
 
 2015-03-13: Version 0.8.1
diff --git a/Makefile.am b/Makefile.am
index 22dbaca..c624ab1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 \
diff --git a/src/libaacs/aacs.c b/src/libaacs/aacs.c
index 6c13f17..60a1a1f 100644
--- a/src/libaacs/aacs.c
+++ b/src/libaacs/aacs.c
@@ -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 */
diff --git a/src/libaacs/content_cert.c b/src/libaacs/content_cert.c
new file mode 100644
index 0000000..995537a
--- /dev/null
+++ b/src/libaacs/content_cert.c
@@ -0,0 +1,78 @@
+/*
+ * 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);
+    }
+}
diff --git a/src/libaacs/content_cert.h b/src/libaacs/content_cert.h
new file mode 100644
index 0000000..b491aba
--- /dev/null
+++ b/src/libaacs/content_cert.h
@@ -0,0 +1,38 @@
+/*
+ * 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_ */
diff --git a/src/libaacs/crypto.c b/src/libaacs/crypto.c
index 1294366..64a403e 100644
--- a/src/libaacs/crypto.c
+++ b/src/libaacs/crypto.c
@@ -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) {
diff --git a/src/libaacs/crypto.h b/src/libaacs/crypto.h
index 0419927..00410f1 100644
--- a/src/libaacs/crypto.h
+++ b/src/libaacs/crypto.h
@@ -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);

_______________________________________________
libaacs-devel mailing list
libaacs-devel@videolan.org
https://mailman.videolan.org/listinfo/libaacs-devel

Reply via email to