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
[email protected]
https://mailman.videolan.org/listinfo/libaacs-devel