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