Petri Hintukainen pushed to branch master at VideoLAN / libaacs


Commits:
2c62afee by npzacs at 2021-05-02T17:49:51+03:00
crypto.h: Trigger warning if return value is not used.

- - - - -
a8a31c2b by npzacs at 2021-05-02T17:50:48+03:00
mkb_dump: check for invalid record size

- - - - -
45310e76 by npzacs at 2021-05-02T17:52:23+03:00
mkb_dump: check revocation list total_entries against data size

- - - - -
e52c9087 by npzacs at 2021-05-02T17:53:30+03:00
Rename local function

- - - - -
73d8eade by npzacs at 2021-05-02T17:57:23+03:00
Validate mkb record size against file size

Avoid huge allocs

- - - - -
92857350 by npzacs at 2021-05-02T18:00:30+03:00
Improve input data validation checks in unit key parsing

- - - - -


5 changed files:

- src/devtools/mkb_dump.c
- src/libaacs/aacs.c
- src/libaacs/crypto.c
- src/libaacs/crypto.h
- src/libaacs/unit_key.c


Changes:

=====================================
src/devtools/mkb_dump.c
=====================================
@@ -93,6 +93,11 @@ static void _dump_aacs1_rl(const uint8_t *rl, size_t rl_size)
     uint32_t total_entries = MKINT_BE32(rl);
     rl += 4; rl_size -= 4;
 
+    if ((size_t)total_entries > rl_size / 8) {
+        printf("  revocation list size mismatch: total_entries=%u\n", 
(unsigned)total_entries);
+        return;
+    }
+
     while (total_entries > 0 && rl_size >= 4) {
         uint32_t entries = MKINT_BE32(rl);
         rl += 4; rl_size -= 4;
@@ -120,7 +125,12 @@ static void _dump_aacs1_rl(const uint8_t *rl, size_t 
rl_size)
         }
         _dump_signature(rl, 40);
         rl += 40; rl_size -= 40;
-        total_entries -= entries;
+        if (total_entries <= entries) {
+            total_entries -= entries;
+        } else {
+            printf("  revocation list size mismatch\n");
+            total_entries = 0;
+        }
     }
 }
 
@@ -143,6 +153,10 @@ static void _dump_record(MKB *mkb, int record)
     for (pos = 0; pos + 4 <= size; pos += len) {
         uint8_t type = data[pos];
         len  = MKINT_BE24(data + pos + 1);
+        if (len > size - pos) {
+            printf("  invalid record 0x%02x size: %zu\n", type, len);
+            break;
+        }
         if (type == record) {
             switch (record) {
                 case 0x02: if (len > 4 && len <= 64) _dump_signature(data + 
pos + 4, len - 4); break;


=====================================
src/libaacs/aacs.c
=====================================
@@ -481,6 +481,7 @@ static size_t _read_mkb_file(AACS *aacs, const char *file, 
void **pdata)
     size_t       data_size = 65536; /* initial alloc */
     uint32_t     chunk_size = 4; /* initial read */
     uint8_t     *data;
+    int64_t      fsize;
 
     *pdata = NULL;
 
@@ -490,6 +491,13 @@ static size_t _read_mkb_file(AACS *aacs, const char *file, 
void **pdata)
         return 0;
     }
 
+    fsize = file_size(fp);
+    if (fsize < 4) {
+        BD_DEBUG(DBG_AACS | DBG_CRIT, "Empty file: %s\n", file);
+        file_close(fp);
+        return 0;
+    }
+
     data = malloc(data_size);
     if (!data) {
         BD_DEBUG(DBG_AACS | DBG_CRIT, "Out of memory\n");
@@ -506,6 +514,10 @@ static size_t _read_mkb_file(AACS *aacs, const char *file, 
void **pdata)
         }
         size += read_size;
         chunk_size = MKINT_BE24(data + size - 4 + 1);
+        if (fsize - size + 4 < (int64_t)chunk_size) {
+            BD_DEBUG(DBG_AACS | DBG_CRIT, "Invalid record size %u in %s\n", 
(unsigned)chunk_size, file);
+            break;
+        }
         if (data_size < size + chunk_size) {
             data_size = 2*size + chunk_size;
             void *tmp = realloc(data, data_size);


=====================================
src/libaacs/crypto.c
=====================================
@@ -713,7 +713,7 @@ int  crypto_aacs_verify_aacscc(const uint8_t *signature, 
const uint8_t *data, ui
     return 0;
 }
 
-static int crypto_aacs_verify_cert(const uint8_t *cert)
+static int _aacs_verify_cert(const uint8_t *cert)
 {
     if (MKINT_BE16(cert+2) != 0x5c) {
         BD_DEBUG(DBG_AACS, "Certificate length is invalid (0x%04x), expected 
0x005c\n",
@@ -738,7 +738,7 @@ int crypto_aacs_verify_host_cert(const uint8_t *cert)
         return 0;
     }
 
-    if (!crypto_aacs_verify_cert(cert)) {
+    if (!_aacs_verify_cert(cert)) {
         BD_DEBUG(DBG_AACS, "Host certificate signature is invalid\n");
         return 0;
     }
@@ -760,7 +760,7 @@ int crypto_aacs_verify_drive_cert(const uint8_t *cert)
         return 0;
     }
 
-    if (!crypto_aacs_verify_cert(cert)) {
+    if (!_aacs_verify_cert(cert)) {
         BD_DEBUG(DBG_AACS, "Drive certificate signature is invalid\n");
         return 0;
     }


=====================================
src/libaacs/crypto.h
=====================================
@@ -32,25 +32,25 @@ BD_PRIVATE void crypto_strerror(int err, char *buf, size_t 
buf_size);
     BD_DEBUG(DBG_CRIT | (flags), "crypto error: %s: %s (%u)\n", (str), s, 
(unsigned)(err)); \
   } while (0)
 
-BD_PRIVATE int  crypto_init(void);
-BD_PRIVATE int  crypto_aes128e(const uint8_t *key, const uint8_t *data, 
uint8_t *dst);
-BD_PRIVATE int  crypto_aes128d(const uint8_t *key, const uint8_t *data, 
uint8_t *dst);
+BD_PRIVATE int  crypto_init(void) BD_USED;
+BD_PRIVATE int  crypto_aes128e(const uint8_t *key, const uint8_t *data, 
uint8_t *dst) BD_USED;
+BD_PRIVATE int  crypto_aes128d(const uint8_t *key, const uint8_t *data, 
uint8_t *dst) BD_USED;
 BD_PRIVATE int  crypto_aesg3(const uint8_t *D, uint8_t *lsubk, uint8_t* rsubk,
-                             uint8_t *pk);   // returns left, centre, right 
keys
-BD_PRIVATE int  crypto_aes_cmac_16(const unsigned char *data, const unsigned 
char *aes_key, unsigned char *cmac);
+                             uint8_t *pk) BD_USED;   // returns left, centre, 
right keys
+BD_PRIVATE int  crypto_aes_cmac_16(const unsigned char *data, const unsigned 
char *aes_key, unsigned char *cmac) BD_USED;
 
-BD_PRIVATE int  crypto_aacs_decrypt(const uint8_t *key, uint8_t *out, size_t 
out_size, const uint8_t *in, size_t in_size);
+BD_PRIVATE int  crypto_aacs_decrypt(const uint8_t *key, uint8_t *out, size_t 
out_size, const uint8_t *in, size_t in_size) BD_USED;
 
 BD_PRIVATE void crypto_aacs_sign(const uint8_t *cert, const uint8_t *priv_key,
                                  uint8_t *signature,
                                  const uint8_t *nonce, const uint8_t *point);
 BD_PRIVATE void crypto_aacs_title_hash(const uint8_t *ukf, uint64_t len, 
uint8_t *hash);
 
-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_host_cert(const uint8_t *cert);
-BD_PRIVATE int  crypto_aacs_verify_drive_cert(const uint8_t *cert);
+BD_PRIVATE int  crypto_aacs_verify(const uint8_t *cert, const uint8_t 
*signature, const uint8_t *data, uint32_t len) BD_USED;
+BD_PRIVATE int  crypto_aacs_verify_aacsla(const uint8_t *signature, const 
uint8_t *data, uint32_t len) BD_USED;
+BD_PRIVATE int  crypto_aacs_verify_aacscc(const uint8_t *signature, const 
uint8_t *data, uint32_t len) BD_USED;
+BD_PRIVATE int  crypto_aacs_verify_host_cert(const uint8_t *cert) BD_USED;
+BD_PRIVATE int  crypto_aacs_verify_drive_cert(const uint8_t *cert) BD_USED;
 
 BD_PRIVATE void crypto_create_host_key_pair(uint8_t *key, uint8_t *key_point);
 BD_PRIVATE void crypto_create_nonce(uint8_t *buf, size_t len);


=====================================
src/libaacs/unit_key.c
=====================================
@@ -153,6 +153,9 @@ static int _parse_uks(AACS_UK *uk, const uint8_t *p, size_t 
size, int aacs2)
     const uint8_t empty_key[16] = {0};
     uint32_t uk_pos;
     unsigned int i;
+    unsigned num_uk;
+
+    uk->num_uk = 0;
 
     if (size < 4) {
         BD_DEBUG(DBG_UK | DBG_CRIT, "Empty unit key file\n");
@@ -163,26 +166,27 @@ static int _parse_uks(AACS_UK *uk, const uint8_t *p, 
size_t size, int aacs2)
 
     uk_pos = MKINT_BE32(p);
 
-    if (size < uk_pos + 2) {
+    if (size - 2 < uk_pos) {
         BD_DEBUG(DBG_UK | DBG_CRIT, "Unexpected EOF (key data missing)\n");
         return -1;
     }
 
-    uk->num_uk = MKINT_BE16(p + uk_pos);
-    if (uk->num_uk < 1) {
+    num_uk = MKINT_BE16(p + uk_pos);
+    if (num_uk < 1) {
         BD_DEBUG(DBG_UK | DBG_CRIT, "No unit keys\n");
         return 0;
     }
-    if (uk->num_uk > 0xffff) {
+
+    if (size - uk_pos < 16) {
+        BD_DEBUG(DBG_UK | DBG_CRIT, "Unexpected EOF (key data truncated)\n");
         return -1;
     }
-
-    if (size < uk_pos + 48 * uk->num_uk + 16) {
+    if ((size - uk_pos - 16) / 48 < num_uk) {
         BD_DEBUG(DBG_UK | DBG_CRIT, "Unexpected EOF (key data truncated)\n");
         return -1;
     }
 
-    if (aacs2 && uk->num_uk > 1) {
+    if (aacs2 && num_uk > 1) {
         /* do some sanity checks ... */
         if (!memcmp(empty_key, p + 48 + 48 + 16, 16)) {
             BD_DEBUG(DBG_UK | DBG_CRIT, "AACS2 unit key not found from 
expected location ?\n");
@@ -195,17 +199,17 @@ static int _parse_uks(AACS_UK *uk, const uint8_t *p, 
size_t size, int aacs2)
 
     /* alloc storage for keys */
 
-    uk->enc_uk = calloc(uk->num_uk, sizeof(AACS_UK));
+    uk->enc_uk = calloc(num_uk, sizeof(AACS_UK));
     if (!uk->enc_uk) {
         BD_DEBUG(DBG_UK | DBG_CRIT, "Out of memory\n");
         return -1;
     }
 
-    BD_DEBUG(DBG_UK, "%d CPS unit keys (AACS%d)\n", uk->num_uk, aacs2 ? 2 : 1);
+    BD_DEBUG(DBG_UK, "%d CPS unit keys (AACS%d)\n", num_uk, aacs2 ? 2 : 1);
 
     /* get encrypted keys */
 
-    for (i = 0; i < uk->num_uk; i++) {
+    for (i = 0; i < num_uk; i++) {
         uk_pos += 48;
         memcpy(uk->enc_uk[i].key, p + uk_pos, 16);
 
@@ -220,6 +224,7 @@ static int _parse_uks(AACS_UK *uk, const uint8_t *p, size_t 
size, int aacs2)
         }
     }
 
+    uk->num_uk = num_uk;
     return 0;
 }
 



View it on GitLab: 
https://code.videolan.org/videolan/libaacs/-/compare/bd0fa5d20c795decdb4b8cd572bcd73ce675e35a...92857350477c35882d9ad12ea3e0903ad2aac77d

-- 
View it on GitLab: 
https://code.videolan.org/videolan/libaacs/-/compare/bd0fa5d20c795decdb4b8cd572bcd73ce675e35a...92857350477c35882d9ad12ea3e0903ad2aac77d
You're receiving this email because of your account on code.videolan.org.


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

Reply via email to