CVE-2026-28590 AI-generated analysis
platform/packages/modules/Bluetooth, system/stack/smp (SMP pairing) and system/stack/btm / system/stack/btu (encryption key size enforcement)
The fix makes the LE Security Manager (SMP) reject a peer Pairing Request/Response whose Maximum Encryption Key Size is below the 7-octet minimum (and adds the same check on the SMP-over-BR/EDR path), routing all minimum-key-size checks through a new btm_sec_get_min_enc_key_size() accessor.
Root cause
In system/stack/smp/smp_act.cc, smp_proc_pair_cmd() parsed the peer's Maximum Encryption Key Size into p_cb->peer_enc_size but only failed pairing with SMP_ENC_KEY_SIZE when p_cb->cert_failure was set to SMP_ENC_KEY_SIZE; it did not compare peer_enc_size against the 7-octet minimum. smp_br_process_pairing_command() (SMP over BR/EDR) had no key-size check before smp_command_has_invalid_parameters(). The 7-octet minimum (file-local MIN_KEY_SIZE in btu_hcif.cc on Android 14) was enforced on BR/EDR via the HCI Read Encryption Key Size completion handlers, and per the commit message the minimum was not enforced for LE.
How the fix works
- system/stack/btm/btm_sec.h: adds constexpr MIN_KEY_SIZE = 7, MIN_KEY_SIZE_DEFAULT = MIN_KEY_SIZE, MAX_KEY_SIZE = 16 and declares uint8_t btm_sec_get_min_enc_key_size(). Also changes the btm_proc_sp_req_evt declaration to take const uint8_t* (declaration-only, no functional effect shown).
- system/stack/btm/btm_sec.cc: new btm_sec_get_min_enc_key_size() returns a static min_key_size initialised to MIN_KEY_SIZE_DEFAULT (7) on Android 14; no sysprop is consulted on this branch.
- system/stack/smp/smp_act.cc:smp_proc_pair_cmd: after reading the six pairing fields, fetches min_key_size = btm_sec_get_min_enc_key_size() and, if p_cb->cert_failure == SMP_ENC_KEY_SIZE OR p_cb->peer_enc_size < min_key_size, logs a warning and raises SMP_AUTH_CMPL_EVT with status SMP_ENC_KEY_SIZE, returning before smp_command_has_invalid_parameters() and before any IO-cap/pairing continuation. This function handles the SMP pairing request/response from the peer.
- system/stack/smp/smp_act.cc:smp_br_process_pairing_command: adds the equivalent check for SMP over BR/EDR, raising SMP_BR_AUTH_CMPL_EVT with status SMP_ENC_KEY_SIZE when peer_enc_size < min_key_size.
- system/stack/btu/btu_hcif.cc: removes the file-local constexpr MIN_KEY_SIZE and makes read_encryption_key_size_complete_after_encryption_change() and read_encryption_key_size_complete_after_key_refresh() compare against btm_sec_get_min_enc_key_size(); includes stack/btm/btm_sec.h. Threshold of the BR/EDR check is unchanged (7 on this branch).
- system/gd/hci/controller.cc: cosmetic only; kMinEncryptionKeySize is copied into a local before building SetMinEncryptionKeySizeBuilder, no functional change.
- system/test/mock/mock_stack_btm_sec.cc: adds a stub btm_sec_get_min_enc_key_size() returning MIN_KEY_SIZE_DEFAULT.
Completeness
- Covers peer Pairing Request and Pairing Response on LE because smp_proc_pair_cmd processes the pairing request/response from the peer, and covers the SMP-over-BR/EDR pairing command path (smp_br_process_pairing_command).
- The existing BR/EDR HCI key-size checks are preserved and now share the same minimum via the accessor; the threshold itself is unchanged (7).
- The check is performed at pairing time only; nothing in the diff re-validates the key size of LTKs already stored from earlier bonds, nor does it touch the local loc_enc_size value or the encryption-start path for LE links.
- On Android 14 and 15 the minimum is a hard-coded 7; only the Android 16 variant honours the android::sysprop::bluetooth::Gap::min_key_size property, clamped to [MIN_KEY_SIZE, MAX_KEY_SIZE].
- The cert_failure branch is merged into the new condition and now always reports SMP_ENC_KEY_SIZE, which is the same value it previously carried.
Behavior changes
- LE pairing with a peer advertising Maximum Encryption Key Size < 7 now fails with SMP status SMP_ENC_KEY_SIZE (SMP_AUTH_CMPL_EVT) and a warning log.
- SMP over BR/EDR pairing commands with key size < 7 now fail with SMP_ENC_KEY_SIZE via SMP_BR_AUTH_CMPL_EVT.
- The new key-size check runs before smp_command_has_invalid_parameters(), so an undersized key is reported as SMP_ENC_KEY_SIZE rather than SMP_INVALID_PARAMETERS even if other parameters are also invalid.
- btu_hcif.cc key-size disconnect logic now calls btm_sec_get_min_enc_key_size() instead of a file-local constant; same threshold on Android 14.
Per major
- Android 14: fix 3475f39c4c16 in android-security-14.0.0_r29 (cherry-pick of 55c96018e4b4): accessor returns constant 7; key-size handlers patched in system/stack/btu/btu_hcif.cc where they live on this branch; plain mock stub; cosmetic controller.cc edit.
- Android 15: adapted fix (f161543f33de in android-security-15.0.0_r17): same smp_act.cc changes (int min_key_size, log::warn); handlers patched in system/stack/btm/btm_sec.cc where they live on this branch; constants are constexpr int; mockcify-style mock struct added in mock_stack_btm_sec.cc/.h; no controller.cc change.
- Android 16: adapted fix (8b61335e4984 in android-security-16.0.0_r8): same smp_act.cc changes; the pre-existing static get_min_enc_key_size() (sysprop Gap::min_key_size clamped to [7,16]) is renamed/exported as btm_sec_get_min_enc_key_size() and constants moved to btm_sec.h; mockcify mock added.
- Android 17: not affected: not listed by the bulletin per the per-major facts; at android-security-17.0.0_r1, 4/8 lines of the patched region are present.
Unknowns
- The concrete security consequence that justified the Critical EoP rating is not described in the material beyond 'key sizes smaller than 7 octets are forbidden'.
- The bulletin's affected list includes '17-next' while the per-major facts say Android 17 is not listed; how 17-next relates to android-security-17.0.0_r1 is not shown.
- Whether existing bonds created with an undersized key before the fix are revalidated or invalidated (nothing in the diff does so).
- What smp_command_has_invalid_parameters() validates (including any key-size range) is not shown in the material.
- What sets p_cb->cert_failure is not shown in the material.
- Why the btm_proc_sp_req_evt declaration was changed to const uint8_t* in the 14 header; the corresponding definition is not in the material.