diff options
| author | jacqueline <me@jacqueline.id.au> | 2024-03-28 14:32:49 +1100 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2024-03-28 14:32:49 +1100 |
| commit | ee29c25b29eaa4fac4e897442634b69ecc8d8125 (patch) | |
| tree | 8c5f1a140463f20f104316fa3492984e191154e9 /lib/bt/host/bluedroid/stack/smp | |
| parent | 239e6d89507a24c849385f4bfa93ac4ad58e5de5 (diff) | |
| download | tangara-fw-ee29c25b29eaa4fac4e897442634b69ecc8d8125.tar.gz | |
Fork ESP-IDF's bluetooth component
i want better sbc encoding, and no cla will stop me
Diffstat (limited to 'lib/bt/host/bluedroid/stack/smp')
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/aes.c | 938 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/include/aes.h | 162 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h | 74 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h | 60 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/include/smp_int.h | 545 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/p_256_curvepara.c | 78 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c | 283 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/p_256_multprecision.c | 647 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/smp_act.c | 2194 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/smp_api.c | 615 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/smp_br_main.c | 369 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/smp_cmac.c | 369 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/smp_keys.c | 2293 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/smp_l2c.c | 344 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/smp_main.c | 810 | ||||
| -rw-r--r-- | lib/bt/host/bluedroid/stack/smp/smp_utils.c | 1645 |
16 files changed, 11426 insertions, 0 deletions
diff --git a/lib/bt/host/bluedroid/stack/smp/aes.c b/lib/bt/host/bluedroid/stack/smp/aes.c new file mode 100644 index 00000000..18b56b87 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/aes.c @@ -0,0 +1,938 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue 09/09/2006 + + This is an AES implementation that uses only 8-bit byte operations on the + cipher state (there are options to use 32-bit types if available). + + The combination of mix columns and byte substitution used here is based on + that developed by Karl Malbrain. His contribution is acknowledged. + */ + +/* define if you have a fast memcpy function on your system */ +#if 1 +# define HAVE_MEMCPY +# include <string.h> +#if 0 +# if defined( _MSC_VER ) +# include <intrin.h> +# pragma intrinsic( memcpy ) +# endif +#endif +#endif + +#include <stdlib.h> + +/* add the target configuration to allow using internal data types and compilation options */ +#include "common/bt_target.h" + +/* define if you have fast 32-bit types on your system */ +#if 1 +# define HAVE_UINT_32T +#endif + +/* define if you don't want any tables */ +#if 1 +# define USE_TABLES +#endif + +/* On Intel Core 2 duo VERSION_1 is faster */ + +/* alternative versions (test for performance on your system) */ +#if 1 +# define VERSION_1 +#endif + +#include "aes.h" + +#if defined( HAVE_UINT_32T ) +typedef UINT32 uint_32t; +#endif + +/* functions for finite field multiplication in the AES Galois field */ + +#define WPOLY 0x011b +#define BPOLY 0x1b +#define DPOLY 0x008d + +#define f1(x) (x) +#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY)) +#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY)) +#define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \ + ^ (((x >> 5) & 4) * WPOLY)) +#define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0)) + +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#if defined( USE_TABLES ) + +#define sb_data(w) { /* S Box data values */ \ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } + +#define isb_data(w) { /* inverse S Box data values */ \ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } + +#define mm_data(w) { /* basic data for forming finite field tables */ \ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } + +static const uint_8t sbox[256] = sb_data(f1); +static const uint_8t isbox[256] = isb_data(f1); + +static const uint_8t gfm2_sbox[256] = sb_data(f2); +static const uint_8t gfm3_sbox[256] = sb_data(f3); + +static const uint_8t gfmul_9[256] = mm_data(f9); +static const uint_8t gfmul_b[256] = mm_data(fb); +static const uint_8t gfmul_d[256] = mm_data(fd); +static const uint_8t gfmul_e[256] = mm_data(fe); + +#define s_box(x) sbox[(x)] +#define is_box(x) isbox[(x)] +#define gfm2_sb(x) gfm2_sbox[(x)] +#define gfm3_sb(x) gfm3_sbox[(x)] +#define gfm_9(x) gfmul_9[(x)] +#define gfm_b(x) gfmul_b[(x)] +#define gfm_d(x) gfmul_d[(x)] +#define gfm_e(x) gfmul_e[(x)] + +#else + +/* this is the high bit of x right shifted by 1 */ +/* position. Since the starting polynomial has */ +/* 9 bits (0x11b), this right shift keeps the */ +/* values of all top bits within a byte */ + +static uint_8t hibit(const uint_8t x) +{ + uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static uint_8t gf_inv(const uint_8t x) +{ + uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if (x < 2) { + return x; + } + + for ( ; ; ) { + if (n1) { + while (n2 >= n1) { /* divide polynomial p2 by p1 */ + n2 /= n1; /* shift smaller polynomial left */ + p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ + v2 ^= (v1 * n2); /* shift accumulated value and */ + n2 = hibit(p2); /* add into result */ + } + } else { + return v1; + } + + if (n2) { /* repeat with values swapped */ + while (n1 >= n2) { + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; + n1 = hibit(p1); + } + } else { + return v2; + } + } +} + +/* The forward and inverse affine transformations used in the S-box */ +uint_8t fwd_affine(const uint_8t x) +{ +#if defined( HAVE_UINT_32T ) + uint_32t w = x; + w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); + return 0x63 ^ ((w ^ (w >> 8)) & 0xff); +#else + return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) + ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4); +#endif +} + +uint_8t inv_affine(const uint_8t x) +{ +#if defined( HAVE_UINT_32T ) + uint_32t w = x; + w = (w << 1) ^ (w << 3) ^ (w << 6); + return 0x05 ^ ((w ^ (w >> 8)) & 0xff); +#else + return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) + ^ (x >> 7) ^ (x >> 5) ^ (x >> 2); +#endif +} + +#define s_box(x) fwd_affine(gf_inv(x)) +#define is_box(x) gf_inv(inv_affine(x)) +#define gfm2_sb(x) f2(s_box(x)) +#define gfm3_sb(x) f3(s_box(x)) +#define gfm_9(x) f9(x) +#define gfm_b(x) fb(x) +#define gfm_d(x) fd(x) +#define gfm_e(x) fe(x) + +#endif + +#if defined( HAVE_MEMCPY ) +# define block_copy_nn(d, s, l) memcpy(d, s, l) +# define block_copy(d, s) memcpy(d, s, N_BLOCK) +#else +# define block_copy_nn(d, s, l) copy_block_nn(d, s, l) +# define block_copy(d, s) copy_block(d, s) +#endif + +#if !defined( HAVE_MEMCPY ) +static void copy_block( void *d, const void *s ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t *)d)[ 0] = ((uint_32t *)s)[ 0]; + ((uint_32t *)d)[ 1] = ((uint_32t *)s)[ 1]; + ((uint_32t *)d)[ 2] = ((uint_32t *)s)[ 2]; + ((uint_32t *)d)[ 3] = ((uint_32t *)s)[ 3]; +#else + ((uint_8t *)d)[ 0] = ((uint_8t *)s)[ 0]; + ((uint_8t *)d)[ 1] = ((uint_8t *)s)[ 1]; + ((uint_8t *)d)[ 2] = ((uint_8t *)s)[ 2]; + ((uint_8t *)d)[ 3] = ((uint_8t *)s)[ 3]; + ((uint_8t *)d)[ 4] = ((uint_8t *)s)[ 4]; + ((uint_8t *)d)[ 5] = ((uint_8t *)s)[ 5]; + ((uint_8t *)d)[ 6] = ((uint_8t *)s)[ 6]; + ((uint_8t *)d)[ 7] = ((uint_8t *)s)[ 7]; + ((uint_8t *)d)[ 8] = ((uint_8t *)s)[ 8]; + ((uint_8t *)d)[ 9] = ((uint_8t *)s)[ 9]; + ((uint_8t *)d)[10] = ((uint_8t *)s)[10]; + ((uint_8t *)d)[11] = ((uint_8t *)s)[11]; + ((uint_8t *)d)[12] = ((uint_8t *)s)[12]; + ((uint_8t *)d)[13] = ((uint_8t *)s)[13]; + ((uint_8t *)d)[14] = ((uint_8t *)s)[14]; + ((uint_8t *)d)[15] = ((uint_8t *)s)[15]; +#endif +} + +static void copy_block_nn( void *d, const void *s, uint_8t nn ) +{ + while ( nn-- ) { + *((uint_8t *)d)++ = *((uint_8t *)s)++; + } +} +#endif + +static void xor_block( void *d, const void *s ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t *)d)[ 0] ^= ((uint_32t *)s)[ 0]; + ((uint_32t *)d)[ 1] ^= ((uint_32t *)s)[ 1]; + ((uint_32t *)d)[ 2] ^= ((uint_32t *)s)[ 2]; + ((uint_32t *)d)[ 3] ^= ((uint_32t *)s)[ 3]; +#else + ((uint_8t *)d)[ 0] ^= ((uint_8t *)s)[ 0]; + ((uint_8t *)d)[ 1] ^= ((uint_8t *)s)[ 1]; + ((uint_8t *)d)[ 2] ^= ((uint_8t *)s)[ 2]; + ((uint_8t *)d)[ 3] ^= ((uint_8t *)s)[ 3]; + ((uint_8t *)d)[ 4] ^= ((uint_8t *)s)[ 4]; + ((uint_8t *)d)[ 5] ^= ((uint_8t *)s)[ 5]; + ((uint_8t *)d)[ 6] ^= ((uint_8t *)s)[ 6]; + ((uint_8t *)d)[ 7] ^= ((uint_8t *)s)[ 7]; + ((uint_8t *)d)[ 8] ^= ((uint_8t *)s)[ 8]; + ((uint_8t *)d)[ 9] ^= ((uint_8t *)s)[ 9]; + ((uint_8t *)d)[10] ^= ((uint_8t *)s)[10]; + ((uint_8t *)d)[11] ^= ((uint_8t *)s)[11]; + ((uint_8t *)d)[12] ^= ((uint_8t *)s)[12]; + ((uint_8t *)d)[13] ^= ((uint_8t *)s)[13]; + ((uint_8t *)d)[14] ^= ((uint_8t *)s)[14]; + ((uint_8t *)d)[15] ^= ((uint_8t *)s)[15]; +#endif +} + +static void copy_and_key( void *d, const void *s, const void *k ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t *)d)[ 0] = ((uint_32t *)s)[ 0] ^ ((uint_32t *)k)[ 0]; + ((uint_32t *)d)[ 1] = ((uint_32t *)s)[ 1] ^ ((uint_32t *)k)[ 1]; + ((uint_32t *)d)[ 2] = ((uint_32t *)s)[ 2] ^ ((uint_32t *)k)[ 2]; + ((uint_32t *)d)[ 3] = ((uint_32t *)s)[ 3] ^ ((uint_32t *)k)[ 3]; +#elif 1 + ((uint_8t *)d)[ 0] = ((uint_8t *)s)[ 0] ^ ((uint_8t *)k)[ 0]; + ((uint_8t *)d)[ 1] = ((uint_8t *)s)[ 1] ^ ((uint_8t *)k)[ 1]; + ((uint_8t *)d)[ 2] = ((uint_8t *)s)[ 2] ^ ((uint_8t *)k)[ 2]; + ((uint_8t *)d)[ 3] = ((uint_8t *)s)[ 3] ^ ((uint_8t *)k)[ 3]; + ((uint_8t *)d)[ 4] = ((uint_8t *)s)[ 4] ^ ((uint_8t *)k)[ 4]; + ((uint_8t *)d)[ 5] = ((uint_8t *)s)[ 5] ^ ((uint_8t *)k)[ 5]; + ((uint_8t *)d)[ 6] = ((uint_8t *)s)[ 6] ^ ((uint_8t *)k)[ 6]; + ((uint_8t *)d)[ 7] = ((uint_8t *)s)[ 7] ^ ((uint_8t *)k)[ 7]; + ((uint_8t *)d)[ 8] = ((uint_8t *)s)[ 8] ^ ((uint_8t *)k)[ 8]; + ((uint_8t *)d)[ 9] = ((uint_8t *)s)[ 9] ^ ((uint_8t *)k)[ 9]; + ((uint_8t *)d)[10] = ((uint_8t *)s)[10] ^ ((uint_8t *)k)[10]; + ((uint_8t *)d)[11] = ((uint_8t *)s)[11] ^ ((uint_8t *)k)[11]; + ((uint_8t *)d)[12] = ((uint_8t *)s)[12] ^ ((uint_8t *)k)[12]; + ((uint_8t *)d)[13] = ((uint_8t *)s)[13] ^ ((uint_8t *)k)[13]; + ((uint_8t *)d)[14] = ((uint_8t *)s)[14] ^ ((uint_8t *)k)[14]; + ((uint_8t *)d)[15] = ((uint_8t *)s)[15] ^ ((uint_8t *)k)[15]; +#else + block_copy(d, s); + xor_block(d, k); +#endif +} + +static void add_round_key( uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK] ) +{ + xor_block(d, k); +} + +static void shift_sub_rows( uint_8t st[N_BLOCK] ) +{ + uint_8t tt; + + st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]); + st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]); + + tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]); + st[ 9] = s_box(st[13]); st[13] = s_box( tt ); + + tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt ); + tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt ); + + tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]); + st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt ); +} + +static void inv_shift_sub_rows( uint_8t st[N_BLOCK] ) +{ + uint_8t tt; + + st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]); + st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]); + + tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]); + st[ 5] = is_box(st[1]); st[ 1] = is_box( tt ); + + tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt ); + tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt ); + + tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]); + st[11] = is_box(st[15]); st[15] = is_box( tt ); +} + +#if defined( VERSION_1 ) +static void mix_sub_columns( uint_8t dt[N_BLOCK] ) +{ + uint_8t st[N_BLOCK]; + block_copy(st, dt); +#else +static void mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] ) +{ +#endif + dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]); + dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]); + dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]); + dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]); + + dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]); + dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]); + dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]); + dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]); + + dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]); + dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]); + dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]); + dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]); + + dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]); + dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]); + dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]); + dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]); +} + +#if defined( VERSION_1 ) +static void inv_mix_sub_columns( uint_8t dt[N_BLOCK] ) +{ + uint_8t st[N_BLOCK]; + block_copy(st, dt); +#else +static void inv_mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] ) +{ +#endif + dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3])); + dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3])); + dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3])); + dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3])); + + dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7])); + dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7])); + dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7])); + dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7])); + + dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11])); + dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11])); + dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11])); + dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11])); + + dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15])); + dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15])); + dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15])); + dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15])); +} + +#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) + +/* Set the cipher key for the pre-keyed version */ +/* NOTE: If the length_type used for the key length is an + unsigned 8-bit character, a key length of 256 bits must + be entered as a length in bytes (valid inputs are hence + 128, 192, 16, 24 and 32). +*/ + +return_type aes_set_key( const unsigned char key[], length_type keylen, aes_context ctx[1] ) +{ + uint_8t cc, rc, hi; + + switch ( keylen ) { + case 16: + case 128: /* length in bits (128 = 8*16) */ + keylen = 16; + break; + case 24: + case 192: /* length in bits (192 = 8*24) */ + keylen = 24; + break; + case 32: + /* case 256: length in bits (256 = 8*32) */ + keylen = 32; + break; + default: + ctx->rnd = 0; + return (return_type) - 1; + } + block_copy_nn(ctx->ksch, key, keylen); + hi = (keylen + 28) << 2; + ctx->rnd = (hi >> 4) - 1; + for ( cc = keylen, rc = 1; cc < hi; cc += 4 ) { + uint_8t tt, t0, t1, t2, t3; + + t0 = ctx->ksch[cc - 4]; + t1 = ctx->ksch[cc - 3]; + t2 = ctx->ksch[cc - 2]; + t3 = ctx->ksch[cc - 1]; + if ( cc % keylen == 0 ) { + tt = t0; + t0 = s_box(t1) ^ rc; + t1 = s_box(t2); + t2 = s_box(t3); + t3 = s_box(tt); + rc = f2(rc); + } else if ( keylen > 24 && cc % keylen == 16 ) { + t0 = s_box(t0); + t1 = s_box(t1); + t2 = s_box(t2); + t3 = s_box(t3); + } + tt = cc - keylen; + ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0; + ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1; + ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2; + ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3; + } + return 0; +} + +#endif + +#if defined( AES_ENC_PREKEYED ) + +/* Encrypt a single block of 16 bytes */ + +/* @breif change the name by snake for avoid the conflict with libcrypto */ +return_type bluedroid_aes_encrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] ) +{ + if ( ctx->rnd ) { + uint_8t s1[N_BLOCK], r; + copy_and_key( s1, in, ctx->ksch ); + + for ( r = 1 ; r < ctx->rnd ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns( s1 ); + add_round_key( s1, ctx->ksch + r * N_BLOCK); + } +#else + { + uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK); + } +#endif + shift_sub_rows( s1 ); + copy_and_key( out, s1, ctx->ksch + r * N_BLOCK ); + } else { + return (return_type) - 1; + } + return 0; +} + +/* CBC encrypt a number of blocks (input and return an IV) */ + +return_type aes_cbc_encrypt( const unsigned char *in, unsigned char *out, + int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] ) +{ + + while (n_block--) { + xor_block(iv, in); + if (bluedroid_aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + memcpy(out, iv, N_BLOCK); + in += N_BLOCK; + out += N_BLOCK; + } + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_DEC_PREKEYED ) + +/* Decrypt a single block of 16 bytes */ + +return_type bluedroid_aes_decrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] ) +{ + if ( ctx->rnd ) { + uint_8t s1[N_BLOCK], r; + copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK ); + inv_shift_sub_rows( s1 ); + + for ( r = ctx->rnd ; --r ; ) +#if defined( VERSION_1 ) + { + add_round_key( s1, ctx->ksch + r * N_BLOCK ); + inv_mix_sub_columns( s1 ); + } +#else + { + uint_8t s2[N_BLOCK]; + copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK ); + inv_mix_sub_columns( s1, s2 ); + } +#endif + copy_and_key( out, s1, ctx->ksch ); + } else { + return (return_type) - 1; + } + return 0; +} + +/* CBC decrypt a number of blocks (input and return an IV) */ + +return_type aes_cbc_decrypt( const unsigned char *in, unsigned char *out, + int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] ) +{ + while (n_block--) { + uint_8t tmp[N_BLOCK]; + + memcpy(tmp, in, N_BLOCK); + if (bluedroid_aes_decrypt(in, out, ctx) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + xor_block(out, iv); + memcpy(iv, tmp, N_BLOCK); + in += N_BLOCK; + out += N_BLOCK; + } + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_ENC_128_OTFK ) + +/* The 'on the fly' encryption key update for for 128 bit keys */ + +static void update_encrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc ) +{ + uint_8t cc; + + k[0] ^= s_box(k[13]) ^ *rc; + k[1] ^= s_box(k[14]); + k[2] ^= s_box(k[15]); + k[3] ^= s_box(k[12]); + *rc = f2( *rc ); + + for (cc = 4; cc < 16; cc += 4 ) { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } +} + +/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ + +void bluedroid_aes_encrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 1; + + if (o_key != key) { + block_copy( o_key, key ); + } + copy_and_key( s1, in, o_key ); + + for ( r = 1 ; r < 10 ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns( s1 ); + update_encrypt_key_128( o_key, &rc ); + add_round_key( s1, o_key ); + } +#else + { + uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + update_encrypt_key_128( o_key, &rc ); + copy_and_key( s1, s2, o_key ); + } +#endif + + shift_sub_rows( s1 ); + update_encrypt_key_128( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_DEC_128_OTFK ) + +/* The 'on the fly' decryption key update for for 128 bit keys */ + +static void update_decrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc ) +{ + uint_8t cc; + + for ( cc = 12; cc > 0; cc -= 4 ) { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + *rc = d2(*rc); + k[0] ^= s_box(k[13]) ^ *rc; + k[1] ^= s_box(k[14]); + k[2] ^= s_box(k[15]); + k[3] ^= s_box(k[12]); +} + +/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ + +void bluedroid_aes_decrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 0x6c; + if (o_key != key) { + block_copy( o_key, key ); + } + + copy_and_key( s1, in, o_key ); + inv_shift_sub_rows( s1 ); + + for ( r = 10 ; --r ; ) +#if defined( VERSION_1 ) + { + update_decrypt_key_128( o_key, &rc ); + add_round_key( s1, o_key ); + inv_mix_sub_columns( s1 ); + } +#else + { + uint_8t s2[N_BLOCK]; + update_decrypt_key_128( o_key, &rc ); + copy_and_key( s2, s1, o_key ); + inv_mix_sub_columns( s1, s2 ); + } +#endif + update_decrypt_key_128( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_ENC_256_OTFK ) + +/* The 'on the fly' encryption key update for for 256 bit keys */ + +static void update_encrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc ) +{ + uint_8t cc; + + k[0] ^= s_box(k[29]) ^ *rc; + k[1] ^= s_box(k[30]); + k[2] ^= s_box(k[31]); + k[3] ^= s_box(k[28]); + *rc = f2( *rc ); + + for (cc = 4; cc < 16; cc += 4) { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + k[16] ^= s_box(k[12]); + k[17] ^= s_box(k[13]); + k[18] ^= s_box(k[14]); + k[19] ^= s_box(k[15]); + + for ( cc = 20; cc < 32; cc += 4 ) { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } +} + +/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */ + +void bluedroid_aes_encrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 1; + if (o_key != key) { + block_copy( o_key, key ); + block_copy( o_key + 16, key + 16 ); + } + copy_and_key( s1, in, o_key ); + + for ( r = 1 ; r < 14 ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns(s1); + if ( r & 1 ) { + add_round_key( s1, o_key + 16 ); + } else { + update_encrypt_key_256( o_key, &rc ); + add_round_key( s1, o_key ); + } + } +#else + { + uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + if ( r & 1 ) { + copy_and_key( s1, s2, o_key + 16 ); + } else { + update_encrypt_key_256( o_key, &rc ); + copy_and_key( s1, s2, o_key ); + } + } +#endif + + shift_sub_rows( s1 ); + update_encrypt_key_256( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_DEC_256_OTFK ) + +/* The 'on the fly' encryption key update for for 256 bit keys */ + +static void update_decrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc ) +{ + uint_8t cc; + + for (cc = 28; cc > 16; cc -= 4) { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + k[16] ^= s_box(k[12]); + k[17] ^= s_box(k[13]); + k[18] ^= s_box(k[14]); + k[19] ^= s_box(k[15]); + + for (cc = 12; cc > 0; cc -= 4) { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + *rc = d2(*rc); + k[0] ^= s_box(k[29]) ^ *rc; + k[1] ^= s_box(k[30]); + k[2] ^= s_box(k[31]); + k[3] ^= s_box(k[28]); +} + +/* Decrypt a single block of 16 bytes with 'on the fly' + 256 bit keying +*/ +void bluedroid_aes_decrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 0x80; + + if (o_key != key) { + block_copy( o_key, key ); + block_copy( o_key + 16, key + 16 ); + } + + copy_and_key( s1, in, o_key ); + inv_shift_sub_rows( s1 ); + + for ( r = 14 ; --r ; ) +#if defined( VERSION_1 ) + { + if ( ( r & 1 ) ) { + update_decrypt_key_256( o_key, &rc ); + add_round_key( s1, o_key + 16 ); + } else { + add_round_key( s1, o_key ); + } + inv_mix_sub_columns( s1 ); + } +#else + { + uint_8t s2[N_BLOCK]; + if ( ( r & 1 ) ) { + update_decrypt_key_256( o_key, &rc ); + copy_and_key( s2, s1, o_key + 16 ); + } else { + copy_and_key( s2, s1, o_key ); + } + inv_mix_sub_columns( s1, s2 ); + } +#endif + copy_and_key( out, s1, o_key ); +} + +#endif diff --git a/lib/bt/host/bluedroid/stack/smp/include/aes.h b/lib/bt/host/bluedroid/stack/smp/include/aes.h new file mode 100644 index 00000000..48495bb1 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/include/aes.h @@ -0,0 +1,162 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue 09/09/2006 + + This is an AES implementation that uses only 8-bit byte operations on the + cipher state. + */ + +#ifndef AES_H +#define AES_H + +#if 1 +# define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */ +#endif +#if 1 +# define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */ +#endif +#if 1 +# define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */ +#endif +#if 1 +# define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */ +#endif +#if 1 +# define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */ +#endif +#if 1 +# define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */ +#endif + +#define N_ROW 4 +#define N_COL 4 +#define N_BLOCK (N_ROW * N_COL) +#define N_MAX_ROUNDS 14 + +typedef unsigned char uint_8t; + +typedef uint_8t return_type; + +/* Warning: The key length for 256 bit keys overflows a byte + (see comment below) +*/ + +typedef uint_8t length_type; + +typedef struct { + uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK]; + uint_8t rnd; +} aes_context; + +/* The following calls are for a precomputed key schedule + + NOTE: If the length_type used for the key length is an + unsigned 8-bit character, a key length of 256 bits must + be entered as a length in bytes (valid inputs are hence + 128, 192, 16, 24 and 32). +*/ + +#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) + +return_type aes_set_key( const unsigned char key[], + length_type keylen, + aes_context ctx[1] ); +#endif + +#if defined( AES_ENC_PREKEYED ) + +return_type bluedroid_aes_encrypt( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const aes_context ctx[1] ); + +return_type aes_cbc_encrypt( const unsigned char *in, + unsigned char *out, + int n_block, + unsigned char iv[N_BLOCK], + const aes_context ctx[1] ); +#endif + +#if defined( AES_DEC_PREKEYED ) + +return_type bluedroid_aes_decrypt( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const aes_context ctx[1] ); + +return_type aes_cbc_decrypt( const unsigned char *in, + unsigned char *out, + int n_block, + unsigned char iv[N_BLOCK], + const aes_context ctx[1] ); +#endif + +/* The following calls are for 'on the fly' keying. In this case the + encryption and decryption keys are different. + + The encryption subroutines take a key in an array of bytes in + key[L] where L is 16, 24 or 32 bytes for key lengths of 128, + 192, and 256 bits respectively. They then encrypts the input + data, in[] with this key and put the reult in the output array + out[]. In addition, the second key array, o_key[L], is used + to output the key that is needed by the decryption subroutine + to reverse the encryption operation. The two key arrays can + be the same array but in this case the original key will be + overwritten. + + In the same way, the decryption subroutines output keys that + can be used to reverse their effect when used for encryption. + + Only 128 and 256 bit keys are supported in these 'on the fly' + modes. +*/ + +#if defined( AES_ENC_128_OTFK ) +void bluedroid_aes_encrypt_128( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], + uint_8t o_key[N_BLOCK] ); +#endif + +#if defined( AES_DEC_128_OTFK ) +void bluedroid_aes_decrypt_128( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], + unsigned char o_key[N_BLOCK] ); +#endif + +#if defined( AES_ENC_256_OTFK ) +void bluedroid_aes_encrypt_256( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], + unsigned char o_key[2 * N_BLOCK] ); +#endif + +#if defined( AES_DEC_256_OTFK ) +void bluedroid_aes_decrypt_256( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], + unsigned char o_key[2 * N_BLOCK] ); +#endif + +#endif diff --git a/lib/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h b/lib/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h new file mode 100644 index 00000000..3b28e0c9 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains simple pairing algorithms using Elliptic Curve Cryptography for private public key + * + ******************************************************************************/ + +#pragma once + +#include "p_256_multprecision.h" +#include "common/bt_target.h" + +typedef unsigned long DWORD; + +typedef struct { + DWORD x[KEY_LENGTH_DWORDS_P256]; + DWORD y[KEY_LENGTH_DWORDS_P256]; + DWORD z[KEY_LENGTH_DWORDS_P256]; +} Point; + +typedef struct { + // curve's coefficients + DWORD a[KEY_LENGTH_DWORDS_P256]; + DWORD b[KEY_LENGTH_DWORDS_P256]; + + //whether a is -3 + int a_minus3; + + // prime modulus + DWORD p[KEY_LENGTH_DWORDS_P256]; + + // Omega, p = 2^m -omega + DWORD omega[KEY_LENGTH_DWORDS_P256]; + + // base point, a point on E of order r + Point G; + +} elliptic_curve_t; + +#if SMP_DYNAMIC_MEMORY == FALSE +extern elliptic_curve_t curve; +extern elliptic_curve_t curve_p256; +#else +extern elliptic_curve_t *curve_ptr; +extern elliptic_curve_t *curve_p256_ptr; +#define curve (*curve_ptr) +#define curve_p256 (*curve_p256_ptr) +#endif + + +void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength); + +bool ECC_CheckPointIsInElliCur_P256(Point *p); + +#define ECC_PointMult(q, p, n, keyLength) ECC_PointMult_Bin_NAF(q, p, n, keyLength) + +void p_256_init_curve(UINT32 keyLength); diff --git a/lib/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h b/lib/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h new file mode 100644 index 00000000..0a33b4e2 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains simple pairing algorithms + * + ******************************************************************************/ +#pragma once + +#include "stack/bt_types.h" + +/* Type definitions */ +typedef unsigned long DWORD; + +#define DWORD_BITS 32 +#define DWORD_BYTES 4 +#define DWORD_BITS_SHIFT 5 + +#define KEY_LENGTH_DWORDS_P192 6 +#define KEY_LENGTH_DWORDS_P256 8 +/* Arithmetic Operations */ + +int multiprecision_compare(DWORD *a, DWORD *b, uint32_t keyLength); +int multiprecision_iszero(DWORD *a, uint32_t keyLength); +void multiprecision_init(DWORD *c, uint32_t keyLength); +void multiprecision_copy(DWORD *c, DWORD *a, uint32_t keyLength); +UINT32 multiprecision_dword_bits (DWORD a); +UINT32 multiprecision_most_signdwords(DWORD *a, uint32_t keyLength); +UINT32 multiprecision_most_signbits(DWORD *a, uint32_t keyLength); +void multiprecision_inv_mod(DWORD *aminus, DWORD *a, uint32_t keyLength); +DWORD multiprecision_add(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); // c=a+b +void multiprecision_add_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); +DWORD multiprecision_sub(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); // c=a-b +void multiprecision_sub_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); +void multiprecision_rshift(DWORD *c, DWORD *a, uint32_t keyLength); // c=a>>1, return carrier +void multiprecision_lshift_mod(DWORD *c, DWORD *a, uint32_t keyLength); // c=a<<b, return carrier +DWORD multiprecision_lshift(DWORD *c, DWORD *a, uint32_t keyLength); // c=a<<b, return carrier +void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); // c=a*b +void multiprecision_mersenns_mult_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); +void multiprecision_mersenns_squa_mod(DWORD *c, DWORD *a, uint32_t keyLength); +DWORD multiprecision_lshift(DWORD *c, DWORD *a, uint32_t keyLength); +void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); +void multiprecision_fast_mod(DWORD *c, DWORD *a); +void multiprecision_fast_mod_P256(DWORD *c, DWORD *a); diff --git a/lib/bt/host/bluedroid/stack/smp/include/smp_int.h b/lib/bt/host/bluedroid/stack/smp/include/smp_int.h new file mode 100644 index 00000000..f3ab7ad4 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/include/smp_int.h @@ -0,0 +1,545 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains internally used SMP definitions + * + ******************************************************************************/ +#ifndef SMP_INT_H +#define SMP_INT_H + +// #if (SMP_INCLUDED == TRUE) + +#include "stack/btu.h" +#include "stack/btm_ble_api.h" +#include "stack/btm_api.h" +#include "stack/smp_api.h" + +#define SMP_MODEL_ENCRYPTION_ONLY 0 /* Legacy mode, Just Works model */ +#define SMP_MODEL_PASSKEY 1 /* Legacy mode, Passkey Entry model, this side inputs the key */ +#define SMP_MODEL_OOB 2 /* Legacy mode, OOB model */ +#define SMP_MODEL_KEY_NOTIF 3 /* Legacy mode, Passkey Entry model, this side displays the key */ +#define SMP_MODEL_SEC_CONN_JUSTWORKS 4 /* Secure Connections mode, Just Works model */ +#define SMP_MODEL_SEC_CONN_NUM_COMP 5 /* Secure Connections mode, Numeric Comparison model */ +#define SMP_MODEL_SEC_CONN_PASSKEY_ENT 6 /* Secure Connections mode, Passkey Entry model, */ +/* this side inputs the key */ +#define SMP_MODEL_SEC_CONN_PASSKEY_DISP 7 /* Secure Connections mode, Passkey Entry model, */ +/* this side displays the key */ +#define SMP_MODEL_SEC_CONN_OOB 8 /* Secure Connections mode, OOB model */ +#define SMP_MODEL_OUT_OF_RANGE 9 +typedef UINT8 tSMP_ASSO_MODEL; + + +#ifndef SMP_MAX_CONN +#define SMP_MAX_CONN 2 +#endif + +#define SMP_WAIT_FOR_RSP_TOUT 30 + +#define SMP_OPCODE_INIT 0x04 + +/* SMP events */ +#define SMP_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ +#define SMP_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP +#define SMP_CONFIRM_EVT SMP_OPCODE_CONFIRM +#define SMP_RAND_EVT SMP_OPCODE_RAND +#define SMP_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED +#define SMP_ENCRPTION_INFO_EVT SMP_OPCODE_ENCRYPT_INFO +#define SMP_MASTER_ID_EVT SMP_OPCODE_MASTER_ID +#define SMP_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO +#define SMP_ID_ADDR_EVT SMP_OPCODE_ID_ADDR +#define SMP_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO +#define SMP_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ + +#define SMP_PAIR_PUBLIC_KEY_EVT SMP_OPCODE_PAIR_PUBLIC_KEY +#define SMP_PAIR_KEYPRESS_NOTIFICATION_EVT SMP_OPCODE_PAIR_KEYPR_NOTIF + +#define SMP_PAIR_COMMITM_EVT SMP_OPCODE_PAIR_COMMITM + +#define SMP_SELF_DEF_EVT (SMP_PAIR_COMMITM_EVT + 1) +#define SMP_KEY_READY_EVT (SMP_SELF_DEF_EVT) +#define SMP_ENCRYPTED_EVT (SMP_SELF_DEF_EVT + 1) +#define SMP_L2CAP_CONN_EVT (SMP_SELF_DEF_EVT + 2) +#define SMP_L2CAP_DISCONN_EVT (SMP_SELF_DEF_EVT + 3) +#define SMP_IO_RSP_EVT (SMP_SELF_DEF_EVT + 4) +#define SMP_API_SEC_GRANT_EVT (SMP_SELF_DEF_EVT + 5) +#define SMP_TK_REQ_EVT (SMP_SELF_DEF_EVT + 6) +#define SMP_AUTH_CMPL_EVT (SMP_SELF_DEF_EVT + 7) +#define SMP_ENC_REQ_EVT (SMP_SELF_DEF_EVT + 8) +#define SMP_BOND_REQ_EVT (SMP_SELF_DEF_EVT + 9) +#define SMP_DISCARD_SEC_REQ_EVT (SMP_SELF_DEF_EVT + 10) + +#define SMP_PAIR_DHKEY_CHCK_EVT SMP_OPCODE_PAIR_DHKEY_CHECK + +#define SMP_PUBL_KEY_EXCH_REQ_EVT (SMP_SELF_DEF_EVT + 11) /* request to start public */ +/* key exchange */ + +#define SMP_LOC_PUBL_KEY_CRTD_EVT (SMP_SELF_DEF_EVT + 12) /* local public key created */ + +#define SMP_BOTH_PUBL_KEYS_RCVD_EVT (SMP_SELF_DEF_EVT + 13) /* both local and peer public */ +/* keys are saved in cb */ + +#define SMP_SC_DHKEY_CMPLT_EVT (SMP_SELF_DEF_EVT + 14) /* DHKey computation is completed,*/ +/* time to start SC phase1 */ + +#define SMP_HAVE_LOC_NONCE_EVT (SMP_SELF_DEF_EVT + 15) /* new local nonce is generated */ +/*and saved in p_cb->rand */ + +#define SMP_SC_PHASE1_CMPLT_EVT (SMP_SELF_DEF_EVT + 16) /* time to start SC phase2 */ + +#define SMP_SC_CALC_NC_EVT (SMP_SELF_DEF_EVT + 17) /* request to calculate number */ +/* for user check. Used only in the */ +/* numeric compare protocol */ + +/* Request to display the number for user check to the user.*/ +/* Used only in the numeric compare protocol */ +#define SMP_SC_DSPL_NC_EVT (SMP_SELF_DEF_EVT + 18) + +#define SMP_SC_NC_OK_EVT (SMP_SELF_DEF_EVT + 19) /* user confirms 'OK' numeric */ +/*comparison request */ + +/* both local and peer DHKey Checks are already present - it is used on slave to prevent race condition */ +#define SMP_SC_2_DHCK_CHKS_PRES_EVT (SMP_SELF_DEF_EVT + 20) + +/* same meaning as SMP_KEY_READY_EVT to separate between SC and legacy actions */ +#define SMP_SC_KEY_READY_EVT (SMP_SELF_DEF_EVT + 21) +#define SMP_KEYPRESS_NOTIFICATION_EVENT (SMP_SELF_DEF_EVT + 22) + +#define SMP_SC_OOB_DATA_EVT (SMP_SELF_DEF_EVT + 23) /* SC OOB data from some */ +/* repository is provided */ + +#define SMP_CR_LOC_SC_OOB_DATA_EVT (SMP_SELF_DEF_EVT + 24) +#define SMP_MAX_EVT SMP_CR_LOC_SC_OOB_DATA_EVT + +typedef UINT8 tSMP_EVENT; + +/* Assumption it's only using the low 8 bits, if bigger than that, need to expand it to 16 bits */ +#define SMP_SEC_KEY_MASK 0x00ff + +#define SMP_PASSKEY_MASK 0xfff00000 + +/* SMP pairing state */ +enum { + SMP_STATE_IDLE, + SMP_STATE_WAIT_APP_RSP, + SMP_STATE_SEC_REQ_PENDING, + SMP_STATE_PAIR_REQ_RSP, + SMP_STATE_WAIT_CONFIRM, + SMP_STATE_CONFIRM, + SMP_STATE_RAND, + SMP_STATE_PUBLIC_KEY_EXCH, + SMP_STATE_SEC_CONN_PHS1_START, + SMP_STATE_WAIT_COMMITMENT, + SMP_STATE_WAIT_NONCE, + SMP_STATE_SEC_CONN_PHS2_START, + SMP_STATE_WAIT_DHK_CHECK, + SMP_STATE_DHK_CHECK, + SMP_STATE_ENCRYPTION_PENDING, + SMP_STATE_BOND_PENDING, + SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA, + SMP_STATE_MAX +}; +typedef UINT8 tSMP_STATE; + +/* SMP over BR/EDR events */ +#define SMP_BR_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ +#define SMP_BR_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP +#define SMP_BR_CONFIRM_EVT SMP_OPCODE_CONFIRM /* not expected over BR/EDR */ +#define SMP_BR_RAND_EVT SMP_OPCODE_RAND /* not expected over BR/EDR */ +#define SMP_BR_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED +#define SMP_BR_ENCRPTION_INFO_EVT SMP_OPCODE_ENCRYPT_INFO /* not expected over BR/EDR */ +#define SMP_BR_MASTER_ID_EVT SMP_OPCODE_MASTER_ID /* not expected over BR/EDR */ +#define SMP_BR_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO +#define SMP_BR_ID_ADDR_EVT SMP_OPCODE_ID_ADDR +#define SMP_BR_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO +#define SMP_BR_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ /* not expected over BR/EDR */ +#define SMP_BR_PAIR_PUBLIC_KEY_EVT SMP_OPCODE_PAIR_PUBLIC_KEY /* not expected over BR/EDR */ +#define SMP_BR_PAIR_DHKEY_CHCK_EVT SMP_OPCODE_PAIR_DHKEY_CHECK /* not expected over BR/EDR */ +#define SMP_BR_PAIR_KEYPR_NOTIF_EVT SMP_OPCODE_PAIR_KEYPR_NOTIF /* not expected over BR/EDR */ +#define SMP_BR_SELF_DEF_EVT SMP_BR_PAIR_KEYPR_NOTIF_EVT +#define SMP_BR_KEY_READY_EVT (SMP_BR_SELF_DEF_EVT + 1) +#define SMP_BR_ENCRYPTED_EVT (SMP_BR_SELF_DEF_EVT + 2) +#define SMP_BR_L2CAP_CONN_EVT (SMP_BR_SELF_DEF_EVT + 3) +#define SMP_BR_L2CAP_DISCONN_EVT (SMP_BR_SELF_DEF_EVT + 4) +#define SMP_BR_KEYS_RSP_EVT (SMP_BR_SELF_DEF_EVT + 5) +#define SMP_BR_API_SEC_GRANT_EVT (SMP_BR_SELF_DEF_EVT + 6) +#define SMP_BR_TK_REQ_EVT (SMP_BR_SELF_DEF_EVT + 7) +#define SMP_BR_AUTH_CMPL_EVT (SMP_BR_SELF_DEF_EVT + 8) +#define SMP_BR_ENC_REQ_EVT (SMP_BR_SELF_DEF_EVT + 9) +#define SMP_BR_BOND_REQ_EVT (SMP_BR_SELF_DEF_EVT + 10) +#define SMP_BR_DISCARD_SEC_REQ_EVT (SMP_BR_SELF_DEF_EVT + 11) +#define SMP_BR_MAX_EVT (SMP_BR_SELF_DEF_EVT + 12) +typedef UINT8 tSMP_BR_EVENT; + +/* SMP over BR/EDR pairing states */ +enum { + SMP_BR_STATE_IDLE = SMP_STATE_IDLE, + SMP_BR_STATE_WAIT_APP_RSP, + SMP_BR_STATE_PAIR_REQ_RSP, + SMP_BR_STATE_BOND_PENDING, + SMP_BR_STATE_MAX +}; +typedef UINT8 tSMP_BR_STATE; + +/* random and encrption activity state */ +enum { + SMP_GEN_COMPARE = 1, + SMP_GEN_CONFIRM, + + SMP_GEN_DIV_LTK, + SMP_GEN_DIV_CSRK, + SMP_GEN_RAND_V, + SMP_GEN_TK, + SMP_GEN_SRAND_MRAND, + SMP_GEN_SRAND_MRAND_CONT, + SMP_GENERATE_PRIVATE_KEY_0_7, + SMP_GENERATE_PRIVATE_KEY_8_15, + SMP_GENERATE_PRIVATE_KEY_16_23, + SMP_GENERATE_PRIVATE_KEY_24_31, + SMP_GEN_NONCE_0_7, + SMP_GEN_NONCE_8_15 +}; + +enum { + SMP_KEY_TYPE_TK, + SMP_KEY_TYPE_CFM, + SMP_KEY_TYPE_CMP, + SMP_KEY_TYPE_PEER_DHK_CHCK, + SMP_KEY_TYPE_STK, + SMP_KEY_TYPE_LTK +}; +typedef struct { + UINT8 key_type; + UINT8 *p_data; +} tSMP_KEY; + +typedef union { + UINT8 *p_data; /* UINT8 type data pointer */ + tSMP_KEY key; + UINT16 reason; + UINT32 passkey; + tSMP_OOB_DATA_TYPE req_oob_type; +} tSMP_INT_DATA; + +/* internal status mask */ +#define SMP_PAIR_FLAGS_WE_STARTED_DD (1) +#define SMP_PAIR_FLAGS_PEER_STARTED_DD (1 << 1) +#define SMP_PAIR_FLAGS_CMD_CONFIRM (1 << SMP_OPCODE_CONFIRM) /* 1 << 3 */ +#define SMP_PAIR_FLAG_ENC_AFTER_PAIR (1 << 4) +#define SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK (1 << 5) /* used on slave to resolve race condition */ +#define SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY (1 << 6) /* used on slave to resolve race condition */ +#define SMP_PAIR_FLAG_HAVE_PEER_COMM (1 << 7) /* used to resolve race condition */ +#define SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY (1 << 8) /* used on slave to resolve race condition */ + +/* check if authentication requirement need MITM protection */ +#define SMP_NO_MITM_REQUIRED(x) (((x) & SMP_AUTH_YN_BIT) == 0) + +#define SMP_ENCRYT_KEY_SIZE 16 +#define SMP_ENCRYT_DATA_SIZE 16 +#define SMP_ECNCRPYT_STATUS HCI_SUCCESS + +typedef struct { + BD_ADDR bd_addr; + BT_HDR *p_copy; +} tSMP_REQ_Q_ENTRY; + +/* SMP control block */ +typedef struct { + tSMP_CALLBACK *p_callback; + TIMER_LIST_ENT rsp_timer_ent; + UINT8 trace_level; + BD_ADDR pairing_bda; + tSMP_STATE state; + BOOLEAN derive_lk; + BOOLEAN id_addr_rcvd; + tBLE_ADDR_TYPE id_addr_type; + BD_ADDR id_addr; + BOOLEAN smp_over_br; + tSMP_BR_STATE br_state; /* if SMP over BR/ERD has priority over SMP */ + UINT8 failure; + UINT8 status; + UINT8 role; + UINT16 flags; + UINT8 cb_evt; + tSMP_SEC_LEVEL sec_level; + BOOLEAN connect_initialized; + BT_OCTET16 confirm; + BT_OCTET16 rconfirm; + BT_OCTET16 rrand; /* for SC this is peer nonce */ + BT_OCTET16 rand; /* for SC this is local nonce */ + BT_OCTET32 private_key; + BT_OCTET32 dhkey; + BT_OCTET16 commitment; + BT_OCTET16 remote_commitment; + BT_OCTET16 local_random; /* local randomizer - passkey or OOB randomizer */ + BT_OCTET16 peer_random; /* peer randomizer - passkey or OOB randomizer */ + BT_OCTET16 dhkey_check; + BT_OCTET16 remote_dhkey_check; + tSMP_PUBLIC_KEY loc_publ_key; + tSMP_PUBLIC_KEY peer_publ_key; + tSMP_OOB_DATA_TYPE req_oob_type; + tSMP_SC_OOB_DATA sc_oob_data; + tSMP_IO_CAP peer_io_caps; + tSMP_IO_CAP local_io_capability; + tSMP_OOB_FLAG peer_oob_flag; + tSMP_OOB_FLAG loc_oob_flag; + tSMP_AUTH_REQ peer_auth_req; + tSMP_AUTH_REQ loc_auth_req; + tSMP_AUTH_REQ auth_mode; + BOOLEAN secure_connections_only_mode_required;/* TRUE if locally SM is required to operate */ + /* either in Secure Connections mode or not at all */ + tSMP_ASSO_MODEL selected_association_model; + BOOLEAN le_secure_connections_mode_is_used; + BOOLEAN le_sc_kp_notif_is_used; + tSMP_SC_KEY_TYPE local_keypress_notification; + tSMP_SC_KEY_TYPE peer_keypress_notification; + UINT8 round; /* authentication stage 1 round for passkey association model */ + UINT32 number_to_display; + BT_OCTET16 mac_key; + UINT8 peer_enc_size; + UINT8 loc_enc_size; + UINT8 peer_i_key; + UINT8 peer_r_key; + UINT8 local_i_key; + UINT8 local_r_key; + + BT_OCTET16 tk; + BT_OCTET16 ltk; + UINT16 div; + BT_OCTET16 csrk; /* storage for local CSRK */ + UINT16 ediv; + BT_OCTET8 enc_rand; + UINT8 rand_enc_proc_state; + UINT8 addr_type; + BD_ADDR local_bda; + BOOLEAN is_pair_cancel; + BOOLEAN discard_sec_req; + UINT8 rcvd_cmd_code; + UINT8 rcvd_cmd_len; + UINT16 total_tx_unacked; + BOOLEAN wait_for_authorization_complete; + BOOLEAN use_static_passkey; + UINT32 static_passkey; + BOOLEAN accept_specified_sec_auth; + tSMP_AUTH_REQ origin_loc_auth_req; +} tSMP_CB; + +/* Server Action functions are of this type */ +typedef void (*tSMP_ACT)(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if SMP_DYNAMIC_MEMORY == FALSE +extern tSMP_CB smp_cb; +#else +extern tSMP_CB *smp_cb_ptr; +#define smp_cb (*smp_cb_ptr) +#endif + +#ifdef __cplusplus +} +#endif + +/* Functions provided by att_main.c */ +extern void smp_init (void); + +/* smp main */ +extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data); + +extern void smp_proc_sec_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_set_fail_nc (BOOLEAN enable); +extern void smp_set_fail_conf (BOOLEAN enable); +extern void smp_set_passk_entry_fail(BOOLEAN enable); +extern void smp_set_oob_fail(BOOLEAN enable); +extern void smp_set_peer_sc_notif(BOOLEAN enable); +extern void smp_aes_cmac_rfc4493_chk (UINT8 *key, UINT8 *msg, UINT8 msg_len, + UINT8 mac_len, UINT8 *mac); +extern void smp_f4_calc_chk (UINT8 *U, UINT8 *V, UINT8 *X, UINT8 *Z, UINT8 *mac); +extern void smp_g2_calc_chk (UINT8 *U, UINT8 *V, UINT8 *X, UINT8 *Y); +extern void smp_h6_calc_chk (UINT8 *key, UINT8 *key_id, UINT8 *mac); +extern void smp_f5_key_calc_chk (UINT8 *w, UINT8 *mac); +extern void smp_f5_mackey_or_ltk_calc_chk(UINT8 *t, UINT8 *counter, + UINT8 *key_id, UINT8 *n1, + UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *length, UINT8 *mac); +extern void smp_f5_calc_chk (UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *mac_key, UINT8 *ltk); +extern void smp_f6_calc_chk (UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, + UINT8 *iocap, UINT8 *a1, UINT8 *a2, UINT8 *mac); +/* smp_main */ +extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data); +extern tSMP_STATE smp_get_state(void); +extern void smp_set_state(tSMP_STATE state); + +/* smp_br_main */ +extern void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data); +extern tSMP_BR_STATE smp_get_br_state(void); +extern void smp_set_br_state(tSMP_BR_STATE state); + + +/* smp_act.c */ +extern void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_process_secure_connection_long_term_key(void); +extern void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); + +/* smp_l2c */ +extern void smp_l2cap_if_init (void); +extern void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf); + +/* smp_util.c */ +extern BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +extern void smp_cb_cleanup(tSMP_CB *p_cb); +extern void smp_reset_control_value(tSMP_CB *p_cb); +extern void smp_proc_pairing_cmpl(tSMP_CB *p_cb); +extern void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey); +extern void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 *p_data); +extern void smp_rsp_timeout(TIMER_LIST_ENT *p_tle); +extern void smp_xor_128(BT_OCTET16 a, const BT_OCTET16 b); +extern BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len, + UINT8 *plain_text, UINT8 pt_len, + tSMP_ENC *p_out); +extern BOOLEAN smp_command_has_invalid_parameters(tSMP_CB *p_cb); +extern void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr); +extern tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB *p_cb); +extern void smp_reverse_array(UINT8 *arr, UINT8 len); +extern UINT8 smp_calculate_random_input(UINT8 *random, UINT8 round); +extern void smp_collect_local_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb); +extern void smp_collect_peer_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb); +extern void smp_collect_local_ble_address(UINT8 *le_addr, tSMP_CB *p_cb); +extern void smp_collect_peer_ble_address(UINT8 *le_addr, tSMP_CB *p_cb); +extern BOOLEAN smp_check_commitment(tSMP_CB *p_cb); +extern void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb); +extern BOOLEAN smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb); +extern void smp_remove_fixed_channel(tSMP_CB *p_cb); +extern BOOLEAN smp_request_oob_data(tSMP_CB *p_cb); + +/* smp_keys.c */ +extern void smp_generate_srand_mrand_confirm (tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_stk (tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_passkey (tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_generate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_create_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_use_oob_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_compute_dhkey(tSMP_CB *p_cb); +extern void smp_calculate_local_commitment(tSMP_CB *p_cb); +extern void smp_calculate_peer_commitment(tSMP_CB *p_cb, BT_OCTET16 output_buf); +extern void smp_calculate_numeric_comparison_display_number(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_calculate_local_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_calculate_peer_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +extern void smp_start_nonce_generation(tSMP_CB *p_cb); +extern BOOLEAN smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb); +extern BOOLEAN smp_calculate_long_term_key_from_link_key(tSMP_CB *p_cb); +extern void smp_calculate_f4(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 z, UINT8 *c); +extern UINT32 smp_calculate_g2(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 *y); +extern BOOLEAN smp_calculate_f5(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *mac_key, UINT8 *ltk); +extern BOOLEAN smp_calculate_f5_mackey_or_long_term_key(UINT8 *t, UINT8 *counter, + UINT8 *key_id, UINT8 *n1, UINT8 *n2, UINT8 *a1, + UINT8 *a2, UINT8 *length, UINT8 *mac); +extern BOOLEAN smp_calculate_f5_key(UINT8 *w, UINT8 *t); +extern BOOLEAN smp_calculate_f6(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, UINT8 *iocap, + UINT8 *a1, UINT8 *a2, UINT8 *f3); +extern BOOLEAN smp_calculate_h6(UINT8 *w, UINT8 *keyid, UINT8 *h2); +extern void smp_save_local_oob_data(tSMP_CB *p_cb); +extern void smp_clear_local_oob_data(void); +extern tSMP_LOC_OOB_DATA *smp_get_local_oob_data(void); +#if SMP_DEBUG == TRUE +extern void smp_debug_print_nbyte_little_endian (UINT8 *p, const UINT8 *key_name, + UINT8 len); +#endif + +/* smp_cmac.c */ +extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length, + UINT16 tlen, UINT8 *p_signature); +extern void print128(BT_OCTET16 x, const UINT8 *key_name); + +// #endif ///BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + +#endif /* SMP_INT_H */ diff --git a/lib/bt/host/bluedroid/stack/smp/p_256_curvepara.c b/lib/bt/host/bluedroid/stack/smp/p_256_curvepara.c new file mode 100644 index 00000000..abf9a8ee --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/p_256_curvepara.c @@ -0,0 +1,78 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains simple pairing algorithms + * + ******************************************************************************/ + +#include <string.h> +#include "p_256_ecc_pp.h" + +void p_256_init_curve(UINT32 keyLength) +{ + elliptic_curve_t *ec; + + if (keyLength == KEY_LENGTH_DWORDS_P256) { + ec = &curve_p256; + + ec->p[7] = 0xFFFFFFFF; + ec->p[6] = 0x00000001; + ec->p[5] = 0x0; + ec->p[4] = 0x0; + ec->p[3] = 0x0; + ec->p[2] = 0xFFFFFFFF; + ec->p[1] = 0xFFFFFFFF; + ec->p[0] = 0xFFFFFFFF; + + memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256 * sizeof(ec->omega[0])); + memset(ec->a, 0, KEY_LENGTH_DWORDS_P256 * sizeof(ec->a[0])); + + ec->a_minus3 = TRUE; + + //b + ec->b[7] = 0x5ac635d8; + ec->b[6] = 0xaa3a93e7; + ec->b[5] = 0xb3ebbd55; + ec->b[4] = 0x769886bc; + ec->b[3] = 0x651d06b0; + ec->b[2] = 0xcc53b0f6; + ec->b[1] = 0x3bce3c3e; + ec->b[0] = 0x27d2604b; + + //base point + ec->G.x[7] = 0x6b17d1f2; + ec->G.x[6] = 0xe12c4247; + ec->G.x[5] = 0xf8bce6e5; + ec->G.x[4] = 0x63a440f2; + ec->G.x[3] = 0x77037d81; + ec->G.x[2] = 0x2deb33a0; + ec->G.x[1] = 0xf4a13945; + ec->G.x[0] = 0xd898c296; + + ec->G.y[7] = 0x4fe342e2; + ec->G.y[6] = 0xfe1a7f9b; + ec->G.y[5] = 0x8ee7eb4a; + ec->G.y[4] = 0x7c0f9e16; + ec->G.y[3] = 0x2bce3357; + ec->G.y[2] = 0x6b315ece; + ec->G.y[1] = 0xcbb64068; + ec->G.y[0] = 0x37bf51f5; + } +} diff --git a/lib/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c b/lib/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c new file mode 100644 index 00000000..1f49c652 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c @@ -0,0 +1,283 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains simple pairing algorithms using Elliptic Curve Cryptography for private public key + * + ******************************************************************************/ +//#include <stdio.h> +//#include <stdlib.h> +#include <string.h> +#include "p_256_ecc_pp.h" +#include "p_256_multprecision.h" +#include "common/bt_target.h" + +#if SMP_DYNAMIC_MEMORY == FALSE +elliptic_curve_t curve; +elliptic_curve_t curve_p256; +#else +elliptic_curve_t *curve_ptr; +elliptic_curve_t *curve_p256_ptr; +#endif + +static void p_256_init_point(Point *q) +{ + memset(q, 0, sizeof(Point)); +} + +static void p_256_copy_point(Point *q, Point *p) +{ + memcpy(q, p, sizeof(Point)); +} + +// q=2q +static void ECC_Double(Point *q, Point *p, uint32_t keyLength) +{ + DWORD t1[KEY_LENGTH_DWORDS_P256]; + DWORD t2[KEY_LENGTH_DWORDS_P256]; + DWORD t3[KEY_LENGTH_DWORDS_P256]; + DWORD *x1; + DWORD *x3; + DWORD *y1; + DWORD *y3; + DWORD *z1; + DWORD *z3; + + if (multiprecision_iszero(p->z, keyLength)) { + multiprecision_init(q->z, keyLength); + return; // return infinity + } + + x1 = p->x; y1 = p->y; z1 = p->z; + x3 = q->x; y3 = q->y; z3 = q->z; + + multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2 + multiprecision_sub_mod(t2, x1, t1, keyLength); // t2=x1-t1 + multiprecision_add_mod(t1, x1, t1, keyLength); // t1=x1+t1 + multiprecision_mersenns_mult_mod(t2, t1, t2, keyLength); // t2=t2*t1 + multiprecision_lshift_mod(t3, t2, keyLength); + multiprecision_add_mod(t2, t3, t2, keyLength); // t2=3t2 + + multiprecision_mersenns_mult_mod(z3, y1, z1, keyLength); // z3=y1*z1 + multiprecision_lshift_mod(z3, z3, keyLength); + + multiprecision_mersenns_squa_mod(y3, y1, keyLength); // y3=y1^2 + multiprecision_lshift_mod(y3, y3, keyLength); + multiprecision_mersenns_mult_mod(t3, y3, x1, keyLength); // t3=y3*x1=x1*y1^2 + multiprecision_lshift_mod(t3, t3, keyLength); + multiprecision_mersenns_squa_mod(y3, y3, keyLength); // y3=y3^2=y1^4 + multiprecision_lshift_mod(y3, y3, keyLength); + + multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2 + multiprecision_lshift_mod(t1, t3, keyLength); // t1=2t3 + multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1 + multiprecision_sub_mod(t1, t3, x3, keyLength); // t1=t3-x3 + multiprecision_mersenns_mult_mod(t1, t1, t2, keyLength); // t1=t1*t2 + multiprecision_sub_mod(y3, t1, y3, keyLength); // y3=t1-y3 +} + +// q=q+p, zp must be 1 +static void ECC_Add(Point *r, Point *p, Point *q, uint32_t keyLength) +{ + DWORD t1[KEY_LENGTH_DWORDS_P256]; + DWORD t2[KEY_LENGTH_DWORDS_P256]; + DWORD *x1; + DWORD *x2; + DWORD *x3; + DWORD *y1; + DWORD *y2; + DWORD *y3; + DWORD *z1; + DWORD *z2; + DWORD *z3; + + x1 = p->x; y1 = p->y; z1 = p->z; + x2 = q->x; y2 = q->y; z2 = q->z; + x3 = r->x; y3 = r->y; z3 = r->z; + + // if Q=infinity, return p + if (multiprecision_iszero(z2, keyLength)) { + p_256_copy_point(r, p); + return; + } + + // if P=infinity, return q + if (multiprecision_iszero(z1, keyLength)) { + p_256_copy_point(r, q); + return; + } + + multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2 + multiprecision_mersenns_mult_mod(t2, z1, t1, keyLength); // t2=t1*z1 + multiprecision_mersenns_mult_mod(t1, x2, t1, keyLength); // t1=t1*x2 + multiprecision_mersenns_mult_mod(t2, y2, t2, keyLength); // t2=t2*y2 + + multiprecision_sub_mod(t1, t1, x1, keyLength); // t1=t1-x1 + multiprecision_sub_mod(t2, t2, y1, keyLength); // t2=t2-y1 + + if (multiprecision_iszero(t1, keyLength)) { + if (multiprecision_iszero(t2, keyLength)) { + ECC_Double(r, q, keyLength) ; + return; + } else { + multiprecision_init(z3, keyLength); + return; // return infinity + } + } + + multiprecision_mersenns_mult_mod(z3, z1, t1, keyLength); // z3=z1*t1 + multiprecision_mersenns_squa_mod(y3, t1, keyLength); // t3=t1^2 + multiprecision_mersenns_mult_mod(z1, y3, t1, keyLength); // t4=t3*t1 + multiprecision_mersenns_mult_mod(y3, y3, x1, keyLength); // t3=t3*x1 + multiprecision_lshift_mod(t1, y3, keyLength); // t1=2*t3 + multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2 + multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1 + multiprecision_sub_mod(x3, x3, z1, keyLength); // x3=x3-t4 + multiprecision_sub_mod(y3, y3, x3, keyLength); // t3=t3-x3 + multiprecision_mersenns_mult_mod(y3, y3, t2, keyLength); // t3=t3*t2 + multiprecision_mersenns_mult_mod(z1, z1, y1, keyLength); // t4=t4*t1 + multiprecision_sub_mod(y3, y3, z1, keyLength); +} + +// Computing the Non-Adjacent Form of a positive integer +static void ECC_NAF(uint8_t *naf, uint32_t *NumNAF, DWORD *k, uint32_t keyLength) +{ + uint32_t sign; + int i = 0; + int j; + uint32_t var; + + while ((var = multiprecision_most_signbits(k, keyLength)) >= 1) { + if (k[0] & 0x01) { // k is odd + sign = (k[0] & 0x03); // 1 or 3 + + // k = k-naf[i] + if (sign == 1) { + k[0] = k[0] & 0xFFFFFFFE; + } else { + k[0] = k[0] + 1; + if (k[0] == 0) { //overflow + j = 1; + do { + k[j]++; + } while (k[j++] == 0); //overflow + } + } + } else { + sign = 0; + } + + multiprecision_rshift(k, k, keyLength); + naf[i / 4] |= (sign) << ((i % 4) * 2); + i++; + } + + *NumNAF = i; +} + +// Binary Non-Adjacent Form for point multiplication +void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength) +{ + uint32_t sign; + UINT8 naf[256 / 4 + 1]; + uint32_t NumNaf; + Point minus_p; + Point r; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P256) { + modp = curve_p256.p; + } else { + modp = curve.p; + } + + p_256_init_point(&r); + multiprecision_init(p->z, keyLength); + p->z[0] = 1; + + // initialization + p_256_init_point(q); + + // -p + multiprecision_copy(minus_p.x, p->x, keyLength); + multiprecision_sub(minus_p.y, modp, p->y, keyLength); + + multiprecision_init(minus_p.z, keyLength); + minus_p.z[0] = 1; + + // NAF + memset(naf, 0, sizeof(naf)); + ECC_NAF(naf, &NumNaf, n, keyLength); + + for (int i = NumNaf - 1; i >= 0; i--) { + p_256_copy_point(&r, q); + ECC_Double(q, &r, keyLength); + sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03; + + if (sign == 1) { + p_256_copy_point(&r, q); + ECC_Add(q, &r, p, keyLength); + } else if (sign == 3) { + p_256_copy_point(&r, q); + ECC_Add(q, &r, &minus_p, keyLength); + } + } + + multiprecision_inv_mod(minus_p.x, q->z, keyLength); + multiprecision_mersenns_squa_mod(q->z, minus_p.x, keyLength); + multiprecision_mersenns_mult_mod(q->x, q->x, q->z, keyLength); + multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength); + multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength); +} + +bool ECC_CheckPointIsInElliCur_P256(Point *p) +{ + /* y^2 % q */ + DWORD y_y_q[KEY_LENGTH_DWORDS_P256] = {0x0}; + /* x^2 % q */ + DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0}; + /* x % q */ + DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0}; + /* x^2, To prevent overflow, the length of the x square here needs to + be expanded to two times the original one. */ + DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0}; + /* y_y_q =(p->y)^2(mod q) */ + multiprecision_mersenns_squa_mod(y_y_q, p->y, KEY_LENGTH_DWORDS_P256); + /* Calculate the value of p->x square, x_x = (p->x)^2 */ + multiprecision_mult(x_x, p->x, p->x, KEY_LENGTH_DWORDS_P256); + /* The function of the elliptic curve is y^2 = x^3 - 3x + b (mod q) ==> + y^2 = (x^2 - 3)*x + b (mod q), + so we calculate the x^2 - 3 value here */ + x_x[0] -= 3; + /* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==> + (x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */ + multiprecision_fast_mod_P256(x_x_q, x_x); + /* x_x = x_x_q * x_q */ + multiprecision_mult(x_x, x_x_q, p->x, KEY_LENGTH_DWORDS_P256); + /* x_q = x_x % q */ + multiprecision_fast_mod_P256(x_q, x_x); + /* Save the result in x_x_q */ + multiprecision_add_mod(x_x_q, x_q, curve_p256.b, KEY_LENGTH_DWORDS_P256); + /* compare the y_y_q and x_x_q, see if they are on a given elliptic curve. */ + if (multiprecision_compare(y_y_q, x_x_q, KEY_LENGTH_DWORDS_P256)) { + return false; + } else { + return true; + } +} diff --git a/lib/bt/host/bluedroid/stack/smp/p_256_multprecision.c b/lib/bt/host/bluedroid/stack/smp/p_256_multprecision.c new file mode 100644 index 00000000..1dbca137 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/p_256_multprecision.c @@ -0,0 +1,647 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains simple pairing algorithms + * + ******************************************************************************/ + +#include <string.h> +#include "common/bt_target.h" +#include "p_256_ecc_pp.h" +#include "p_256_multprecision.h" + +void multiprecision_init(DWORD *c, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) { + c[i] = 0; + } +} + +void multiprecision_copy(DWORD *c, DWORD *a, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) { + c[i] = a[i]; + } +} + +int multiprecision_compare(DWORD *a, DWORD *b, uint32_t keyLength) +{ + for (int i = keyLength - 1; i >= 0; i--) { + if (a[i] > b[i]) { + return 1; + } + if (a[i] < b[i]) { + return -1; + } + } + return 0; +} + +int multiprecision_iszero(DWORD *a, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) + if (a[i]) { + return 0; + } + + return 1; +} + +UINT32 multiprecision_dword_bits(DWORD a) +{ + uint32_t i; + for (i = 0; i < DWORD_BITS; i++, a >>= 1) + if (a == 0) { + break; + } + + return i; +} + +UINT32 multiprecision_most_signdwords(DWORD *a, uint32_t keyLength) +{ + int i; + for (i = keyLength - 1; i >= 0; i--) + if (a[i]) { + break; + } + return (i + 1); +} + +UINT32 multiprecision_most_signbits(DWORD *a, uint32_t keyLength) +{ + int aMostSignDWORDs; + + aMostSignDWORDs = multiprecision_most_signdwords(a, keyLength); + if (aMostSignDWORDs == 0) { + return 0; + } + + return (((aMostSignDWORDs - 1) << DWORD_BITS_SHIFT) + + multiprecision_dword_bits(a[aMostSignDWORDs - 1]) ); +} + +DWORD multiprecision_add(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD carrier; + DWORD temp; + + carrier = 0; + for (uint32_t i = 0; i < keyLength; i++) { + temp = a[i] + carrier; + carrier = (temp < carrier); + temp += b[i]; + carrier |= (temp < b[i]); + c[i] = temp; + } + + return carrier; +} + +//c=a-b +DWORD multiprecision_sub(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD borrow; + DWORD temp; + + borrow = 0; + for (uint32_t i = 0; i < keyLength; i++) { + temp = a[i] - borrow; + borrow = (temp > a[i]); + c[i] = temp - b[i]; + borrow |= (c[i] > temp); + } + + return borrow; +} + +// c = a << 1 +void multiprecision_lshift_mod(DWORD *c, DWORD *a, uint32_t keyLength) +{ + DWORD carrier; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P192) { + modp = curve.p; + } else if (keyLength == KEY_LENGTH_DWORDS_P256) { + modp = curve_p256.p; + } else { + return; + } + + carrier = multiprecision_lshift(c, a, keyLength); + if (carrier) { + multiprecision_sub(c, c, modp, keyLength); + } else if (multiprecision_compare(c, modp, keyLength) >= 0) { + multiprecision_sub(c, c, modp, keyLength); + } +} + +// c=a>>1 +void multiprecision_rshift(DWORD *c, DWORD *a, uint32_t keyLength) +{ + int j; + DWORD b = 1; + + j = DWORD_BITS - b; + + DWORD carrier = 0; + DWORD temp; + for (int i = keyLength - 1; i >= 0; i--) { + temp = a[i]; // in case of c==a + c[i] = (temp >> b) | carrier; + carrier = temp << j; + } +} + +// Curve specific optimization when p is a pseudo-Mersenns prime, p=2^(KEY_LENGTH_BITS)-omega +void multiprecision_mersenns_mult_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD cc[2 * KEY_LENGTH_DWORDS_P256]; + + multiprecision_mult(cc, a, b, keyLength); + if (keyLength == 6) { + multiprecision_fast_mod(c, cc); + } else if (keyLength == 8) { + multiprecision_fast_mod_P256(c, cc); + } +} + +// Curve specific optimization when p is a pseudo-Mersenns prime +void multiprecision_mersenns_squa_mod(DWORD *c, DWORD *a, uint32_t keyLength) +{ + multiprecision_mersenns_mult_mod(c, a, a, keyLength); +} + +// c=(a+b) mod p, b<p, a<p +void multiprecision_add_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD carrier; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P192) { + modp = curve.p; + } else if (keyLength == KEY_LENGTH_DWORDS_P256) { + modp = curve_p256.p; + } else { + return; + } + + carrier = multiprecision_add(c, a, b, keyLength); + if (carrier) { + multiprecision_sub(c, c, modp, keyLength); + } else if (multiprecision_compare(c, modp, keyLength) >= 0) { + multiprecision_sub(c, c, modp, keyLength); + } +} + +// c=(a-b) mod p, a<p, b<p +void multiprecision_sub_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD borrow; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P192) { + modp = curve.p; + } else if (keyLength == KEY_LENGTH_DWORDS_P256) { + modp = curve_p256.p; + } else { + return; + } + + borrow = multiprecision_sub(c, a, b, keyLength); + if (borrow) { + multiprecision_add(c, c, modp, keyLength); + } +} + +// c=a<<b, b<DWORD_BITS, c has a buffer size of NumDWORDs+1 +DWORD multiprecision_lshift(DWORD *c, DWORD *a, uint32_t keyLength) +{ + int j; + uint32_t b = 1; + j = DWORD_BITS - b; + + DWORD carrier = 0; + DWORD temp; + + for (uint32_t i = 0; i < keyLength; i++) { + temp = a[i]; // in case c==a + c[i] = (temp << b) | carrier; + carrier = temp >> j; + } + + return carrier; +} + +// c=a*b; c must have a buffer of 2*Key_LENGTH_DWORDS, c != a != b +void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD W; + DWORD U; + DWORD V; + + U = V = W = 0; + multiprecision_init(c, keyLength); + + //assume little endian right now + for (uint32_t i = 0; i < keyLength; i++) { + U = 0; + for (uint32_t j = 0; j < keyLength; j++) { + uint64_t result; + result = ((UINT64)a[i]) * ((uint64_t) b[j]); + W = result >> 32; + V = a[i] * b[j]; + V = V + U; + U = (V < U); + U += W; + V = V + c[i + j]; + U += (V < c[i + j]); + c[i + j] = V; + } + c[i + keyLength] = U; + } +} + +void multiprecision_fast_mod(DWORD *c, DWORD *a) +{ + DWORD U; + DWORD V; + DWORD *modp = curve.p; + + c[0] = a[0] + a[6]; + U = c[0] < a[0]; + c[0] += a[10]; + U += c[0] < a[10]; + + c[1] = a[1] + U; + U = c[1] < a[1]; + c[1] += a[7]; + U += c[1] < a[7]; + c[1] += a[11]; + U += c[1] < a[11]; + + c[2] = a[2] + U; + U = c[2] < a[2]; + c[2] += a[6]; + U += c[2] < a[6]; + c[2] += a[8]; + U += c[2] < a[8]; + c[2] += a[10]; + U += c[2] < a[10]; + + c[3] = a[3] + U; + U = c[3] < a[3]; + c[3] += a[7]; + U += c[3] < a[7]; + c[3] += a[9]; + U += c[3] < a[9]; + c[3] += a[11]; + U += c[3] < a[11]; + + c[4] = a[4] + U; + U = c[4] < a[4]; + c[4] += a[8]; + U += c[4] < a[8]; + c[4] += a[10]; + U += c[4] < a[10]; + + c[5] = a[5] + U; + U = c[5] < a[5]; + c[5] += a[9]; + U += c[5] < a[9]; + c[5] += a[11]; + U += c[5] < a[11]; + + c[0] += U; + V = c[0] < U; + c[1] += V; + V = c[1] < V; + c[2] += V; + V = c[2] < V; + c[2] += U; + V = c[2] < U; + c[3] += V; + V = c[3] < V; + c[4] += V; + V = c[4] < V; + c[5] += V; + V = c[5] < V; + + if (V) { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192); + } else if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P192) >= 0) { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192); + } +} + +void multiprecision_fast_mod_P256(DWORD *c, DWORD *a) +{ + DWORD A; + DWORD B; + DWORD C; + DWORD D; + DWORD E; + DWORD F; + DWORD G; + uint8_t UA; + uint8_t UB; + uint8_t UC; + uint8_t UD; + uint8_t UE; + uint8_t UF; + uint8_t UG; + DWORD U; + DWORD *modp = curve_p256.p; + + // C = a[13] + a[14] + a[15]; + C = a[13]; + C += a[14]; + UC = (C < a[14]); + C += a[15]; + UC += (C < a[15]); + + // E = a[8] + a[9]; + E = a[8]; + E += a[9]; + UE = (E < a[9]); + + // F = a[9] + a[10]; + F = a[9]; + F += a[10]; + UF = (F < a[10]); + + // G = a[10] + a[11] + G = a[10]; + G += a[11]; + UG = (G < a[11]); + + // B = a[12] + a[13] + a[14] + a[15] == C + a[12] + B = C; + UB = UC; + B += a[12]; + UB += (B < a[12]); + + // A = a[11] + a[12] + a[13] + a[14] == B + a[11] - a[15] + A = B; + UA = UB; + A += a[11]; + UA += (A < a[11]); + UA -= (A < a[15]); + A -= a[15]; + + // D = a[10] + a[11] + a[12] + a[13] == A + a[10] - a[14] + D = A; + UD = UA; + D += a[10]; + UD += (D < a[10]); + UD -= (D < a[14]); + D -= a[14]; + + c[0] = a[0]; + c[0] += E; + U = (c[0] < E); + U += UE; + U -= (c[0] < A); + U -= UA; + c[0] -= A; + + if (U & 0x80000000) { + DWORD UU; + UU = 0 - U; + U = (a[1] < UU); + c[1] = a[1] - UU; + } else { + c[1] = a[1] + U; + U = (c[1] < a[1]); + } + + c[1] += F; + U += (c[1] < F); + U += UF; + U -= (c[1] < B); + U -= UB; + c[1] -= B; + + if (U & 0x80000000) { + DWORD UU; + UU = 0 - U; + U = (a[2] < UU); + c[2] = a[2] - UU; + } else { + c[2] = a[2] + U; + U = (c[2] < a[2]); + } + + c[2] += G; + U += (c[2] < G); + U += UG; + U -= (c[2] < C); + U -= UC; + c[2] -= C; + + if (U & 0x80000000) { + DWORD UU; + UU = 0 - U; + U = (a[3] < UU); + c[3] = a[3] - UU; + } else { + c[3] = a[3] + U; + U = (c[3] < a[3]); + } + + c[3] += A; + U += (c[3] < A); + U += UA; + c[3] += a[11]; + U += (c[3] < a[11]); + c[3] += a[12]; + U += (c[3] < a[12]); + U -= (c[3] < a[14]); + c[3] -= a[14]; + U -= (c[3] < a[15]); + c[3] -= a[15]; + U -= (c[3] < E); + U -= UE; + c[3] -= E; + + if (U & 0x80000000) { + DWORD UU; + UU = 0 - U; + U = (a[4] < UU); + c[4] = a[4] - UU; + } else { + c[4] = a[4] + U; + U = (c[4] < a[4]); + } + + c[4] += B; + U += (c[4] < B); + U += UB; + U -= (c[4] < a[15]); + c[4] -= a[15]; + c[4] += a[12]; + U += (c[4] < a[12]); + c[4] += a[13]; + U += (c[4] < a[13]); + U -= (c[4] < F); + U -= UF; + c[4] -= F; + + if (U & 0x80000000) { + DWORD UU; + UU = 0 - U; + U = (a[5] < UU); + c[5] = a[5] - UU; + } else { + c[5] = a[5] + U; + U = (c[5] < a[5]); + } + + c[5] += C; + U += (c[5] < C); + U += UC; + c[5] += a[13]; + U += (c[5] < a[13]); + c[5] += a[14]; + U += (c[5] < a[14]); + U -= (c[5] < G); + U -= UG; + c[5] -= G; + + if (U & 0x80000000) { + DWORD UU; + UU = 0 - U; + U = (a[6] < UU); + c[6] = a[6] - UU; + } else { + c[6] = a[6] + U; + U = (c[6] < a[6]); + } + + c[6] += C; + U += (c[6] < C); + U += UC; + c[6] += a[14]; + U += (c[6] < a[14]); + c[6] += a[14]; + U += (c[6] < a[14]); + c[6] += a[15]; + U += (c[6] < a[15]); + U -= (c[6] < E); + U -= UE; + c[6] -= E; + + if (U & 0x80000000) { + DWORD UU; + UU = 0 - U; + U = (a[7] < UU); + c[7] = a[7] - UU; + } else { + c[7] = a[7] + U; + U = (c[7] < a[7]); + } + + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[8]; + U += (c[7] < a[8]); + U -= (c[7] < D); + U -= UD; + c[7] -= D; + + if (U & 0x80000000) { + while (U) { + multiprecision_add(c, c, modp, KEY_LENGTH_DWORDS_P256); + U++; + } + } else if (U) { + while (U) { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256); + U--; + } + } + + if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P256) >= 0) { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256); + } + +} + +void multiprecision_inv_mod(DWORD *aminus, DWORD *u, uint32_t keyLength) +{ + DWORD v[KEY_LENGTH_DWORDS_P256]; + DWORD A[KEY_LENGTH_DWORDS_P256 + 1]; + DWORD C[KEY_LENGTH_DWORDS_P256 + 1]; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P256) { + modp = curve_p256.p; + } else { + modp = curve.p; + } + + multiprecision_copy(v, modp, keyLength); + multiprecision_init(A, keyLength); + multiprecision_init(C, keyLength); + A[0] = 1; + + while (!multiprecision_iszero(u, keyLength)) { + while (!(u[0] & 0x01)) { // u is even + multiprecision_rshift(u, u, keyLength); + if (!(A[0] & 0x01)) { // A is even + multiprecision_rshift(A, A, keyLength); + } else { + A[keyLength] = multiprecision_add(A, A, modp, keyLength); // A =A+p + multiprecision_rshift(A, A, keyLength); + A[keyLength - 1] |= (A[keyLength] << 31); + } + } + + while (!(v[0] & 0x01)) { // v is even + multiprecision_rshift(v, v, keyLength); + if (!(C[0] & 0x01)) { // C is even + multiprecision_rshift(C, C, keyLength); + } else { + C[keyLength] = multiprecision_add(C, C, modp, keyLength); // C =C+p + multiprecision_rshift(C, C, keyLength); + C[keyLength - 1] |= (C[keyLength] << 31); + } + } + + if (multiprecision_compare(u, v, keyLength) >= 0) { + multiprecision_sub(u, u, v, keyLength); + multiprecision_sub_mod(A, A, C, keyLength); + } else { + multiprecision_sub(v, v, u, keyLength); + multiprecision_sub_mod(C, C, A, keyLength); + } + } + + if (multiprecision_compare(C, modp, keyLength) >= 0) { + multiprecision_sub(aminus, C, modp, keyLength); + } else { + multiprecision_copy(aminus, C, keyLength); + } +} diff --git a/lib/bt/host/bluedroid/stack/smp/smp_act.c b/lib/bt/host/bluedroid/stack/smp/smp_act.c new file mode 100644 index 00000000..0e7dcd5b --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/smp_act.c @@ -0,0 +1,2194 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include <string.h> +#include "device/interop.h" +#include "common/bt_target.h" +#include "btm_int.h" +#include "stack/l2c_api.h" +#include "smp_int.h" +#include "p_256_ecc_pp.h" +//#include "utils/include/bt_utils.h" + +#if SMP_INCLUDED == TRUE +const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = { + /* initiator */ + { {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* Display Only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* SMP_CAP_IO = 1 */ + {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* keyboard only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},/* No Input No Output */ + {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF} + }, /* keyboard display */ + /* responder */ + { {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* Display Only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* SMP_CAP_IO = 1 */ + {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* keyboard only */ + {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},/* No Input No Output */ + {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY} + } /* keyboard display */ + /* display only */ /*SMP_CAP_IO = 1 */ /* keyboard only */ /* No InputOutput */ /* keyboard display */ +}; + +#define SMP_KEY_DIST_TYPE_MAX 4 +const tSMP_ACT smp_distribute_act [] = { +#if (BLE_INCLUDED == TRUE) + smp_generate_ltk, + smp_send_id_info, + smp_generate_csrk, + smp_set_derive_link_key +#else + NULL, + NULL, + NULL, + NULL +#endif ///BLE_INCLUDED == TRUE +}; + +extern UINT8 bta_dm_co_ble_get_accept_auth_enable(void); +extern UINT8 bta_dm_co_ble_get_auth_req(void); + +static bool lmp_version_below(BD_ADDR bda, uint8_t version) +{ + tACL_CONN *acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE); + if (acl == NULL || acl->lmp_version == 0) { + SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__); + return false; + } + SMP_TRACE_DEBUG("%s LMP version %d < %d", __func__, acl->lmp_version, version); + return acl->lmp_version < version; +} + +/******************************************************************************* +** Function smp_update_key_mask +** Description This function updates the key mask for sending or receiving. +*******************************************************************************/ +static void smp_update_key_mask (tSMP_CB *p_cb, UINT8 key_type, BOOLEAN recv) +{ + SMP_TRACE_DEBUG("%s before update role=%d recv=%d local_i_key = %02x, local_r_key = %02x\n", + __func__, p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key); + + if (((p_cb->le_secure_connections_mode_is_used) || + (p_cb->smp_over_br)) && + ((key_type == SMP_SEC_KEY_TYPE_ENC) || (key_type == SMP_SEC_KEY_TYPE_LK))) { + /* in LE SC mode LTK, CSRK and BR/EDR LK are derived locally instead of + ** being exchanged with the peer */ + p_cb->local_i_key &= ~key_type; + p_cb->local_r_key &= ~key_type; + } else if (p_cb->role == HCI_ROLE_SLAVE) { + if (recv) { + p_cb->local_i_key &= ~key_type; + } else { + p_cb->local_r_key &= ~key_type; + } + } else { + if (recv) { + p_cb->local_r_key &= ~key_type; + } else { + p_cb->local_i_key &= ~key_type; + } + } + + SMP_TRACE_DEBUG("updated local_i_key = %02x, local_r_key = %02x\n", p_cb->local_i_key, + p_cb->local_r_key); +} + +/******************************************************************************* +** Function smp_send_app_cback +** Description notifies application about the events the application is interested in +*******************************************************************************/ +void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_EVT_DATA cb_data; + tSMP_STATUS callback_rc; + SMP_TRACE_DEBUG("%s p_cb->cb_evt=%d\n", __func__, p_cb->cb_evt); + if (p_cb->p_callback && p_cb->cb_evt != 0) { + switch (p_cb->cb_evt) { + case SMP_IO_CAP_REQ_EVT: + cb_data.io_req.auth_req = p_cb->peer_auth_req; + cb_data.io_req.oob_data = SMP_OOB_NONE; + cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS; + cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE; + cb_data.io_req.init_keys = p_cb->local_i_key ; + cb_data.io_req.resp_keys = p_cb->local_r_key ; + SMP_TRACE_DEBUG ( "io_cap = %d", cb_data.io_req.io_cap); + break; + + case SMP_NC_REQ_EVT: + cb_data.passkey = p_data->passkey; + break; + case SMP_SC_OOB_REQ_EVT: + cb_data.req_oob_type = p_data->req_oob_type; + break; + case SMP_SC_LOC_OOB_DATA_UP_EVT: + cb_data.loc_oob_data = p_cb->sc_oob_data.loc_oob_data; + break; + + case SMP_BR_KEYS_REQ_EVT: + cb_data.io_req.auth_req = 0; + cb_data.io_req.oob_data = SMP_OOB_NONE; + cb_data.io_req.io_cap = 0; + cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE; + cb_data.io_req.init_keys = SMP_BR_SEC_DEFAULT_KEY; + cb_data.io_req.resp_keys = SMP_BR_SEC_DEFAULT_KEY; + break; + + default: + break; + } + + callback_rc = (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, &cb_data); + + SMP_TRACE_DEBUG("callback_rc=%d p_cb->cb_evt=%d\n", callback_rc, p_cb->cb_evt ); + + if (callback_rc == SMP_SUCCESS) { + switch (p_cb->cb_evt) { + case SMP_IO_CAP_REQ_EVT: + p_cb->loc_auth_req = cb_data.io_req.auth_req; + p_cb->local_io_capability = cb_data.io_req.io_cap; + p_cb->loc_oob_flag = cb_data.io_req.oob_data; + p_cb->loc_enc_size = cb_data.io_req.max_key_size; + p_cb->local_i_key = cb_data.io_req.init_keys; + p_cb->local_r_key = cb_data.io_req.resp_keys; + + if (!(p_cb->loc_auth_req & SMP_AUTH_BOND)) { + SMP_TRACE_WARNING ("Non bonding: No keys will be exchanged"); + p_cb->local_i_key = 0; + p_cb->local_r_key = 0; + } + + SMP_TRACE_DEBUG ("rcvd auth_req: 0x%02x, io_cap: %d \ + loc_oob_flag: %d loc_enc_size: %d," + "local_i_key: 0x%02x, local_r_key: 0x%02x\n", + p_cb->loc_auth_req, p_cb->local_io_capability, p_cb->loc_oob_flag, + p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key); + + p_cb->secure_connections_only_mode_required = + (btm_cb.security_mode == BTM_SEC_MODE_SC) ? TRUE : FALSE; + + if (p_cb->secure_connections_only_mode_required) { + p_cb->loc_auth_req |= SMP_SC_SUPPORT_BIT; + } + + if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) + || lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2) + || interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, + (const bt_bdaddr_t *)&p_cb->pairing_bda)) { + p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT; + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + + SMP_TRACE_DEBUG("set auth_req: 0x%02x, local_i_key: 0x%02x, local_r_key: 0x%02x\n", + p_cb->loc_auth_req, p_cb->local_i_key, p_cb->local_r_key); + + smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL); + break; +#if (CLASSIC_BT_INCLUDED == TRUE) + case SMP_BR_KEYS_REQ_EVT: + p_cb->loc_enc_size = cb_data.io_req.max_key_size; + p_cb->local_i_key = cb_data.io_req.init_keys; + p_cb->local_r_key = cb_data.io_req.resp_keys; + + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + + SMP_TRACE_WARNING ( "for SMP over BR max_key_size: 0x%02x,\ + local_i_key: 0x%02x, local_r_key: 0x%02x\n", + p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key); + + smp_br_state_machine_event(p_cb, SMP_BR_KEYS_RSP_EVT, NULL); + break; +#endif ///CLASSIC_BT_INCLUDED == TRUE + } + } + } + + if (!p_cb->cb_evt && p_cb->discard_sec_req) { + p_cb->discard_sec_req = FALSE; + smp_sm_event(p_cb, SMP_DISCARD_SEC_REQ_EVT, NULL); + } + + SMP_TRACE_DEBUG("%s return\n", __func__); +} + +/******************************************************************************* +** Function smp_send_pair_fail +** Description pairing failure to peer device if needed. +*******************************************************************************/ +void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + p_cb->status = *(UINT8 *)p_data; + p_cb->failure = *(UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s status=%d failure=%d ", __func__, p_cb->status, p_cb->failure); + + if (p_cb->status <= SMP_MAX_FAIL_RSN_PER_SPEC && p_cb->status != SMP_SUCCESS) { + smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb); + p_cb->wait_for_authorization_complete = TRUE; + } +} + +/******************************************************************************* +** Function smp_send_pair_req +** Description actions related to sending pairing request +*******************************************************************************/ +void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + +#if (BLE_INCLUDED == TRUE) + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + /* erase all keys when master sends pairing req*/ + if (p_dev_rec) { + btm_sec_clear_ble_keys(p_dev_rec); + } +#endif ///BLE_INCLUDED == TRUE + /* do not manipulate the key, let app decide, + leave out to BTM to mandate key distribution for bonding case */ + smp_send_cmd(SMP_OPCODE_PAIRING_REQ, p_cb); +} + +/******************************************************************************* +** Function smp_send_pair_rsp +** Description actions related to sending pairing response +*******************************************************************************/ +void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + +#if (BLE_INCLUDED == TRUE) + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + + if (smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb)) { + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) { + smp_use_oob_private_key(p_cb, NULL); + } else { + smp_decide_association_model(p_cb, NULL); + } + } +#endif ///BLE_INCLUDED == TRUE +} + +/******************************************************************************* +** Function smp_send_confirm +** Description send confirmation to the peer +*******************************************************************************/ +void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb); +} + +#if 0 //Unused +/******************************************************************************* +** Function smp_send_init +** Description process pairing initializer to slave device +*******************************************************************************/ +void smp_send_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_send_cmd(SMP_OPCODE_INIT, p_cb); +} +#endif + +/******************************************************************************* +** Function smp_send_rand +** Description send pairing random to the peer +*******************************************************************************/ +void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_send_cmd(SMP_OPCODE_RAND, p_cb); +} + +/******************************************************************************* +** Function smp_send_pair_public_key +** Description send pairing public key command to the peer +*******************************************************************************/ +void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_PUBLIC_KEY, p_cb); +} + +/******************************************************************************* +** Function SMP_SEND_COMMITMENT +** Description send commitment command to the peer +*******************************************************************************/ +void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_COMMITM, p_cb); +} + +/******************************************************************************* +** Function smp_send_dhkey_check +** Description send DHKey Check command to the peer +*******************************************************************************/ +void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + smp_send_cmd(SMP_OPCODE_PAIR_DHKEY_CHECK, p_cb); +} + +/******************************************************************************* +** Function smp_send_keypress_notification +** Description send Keypress Notification command to the peer +*******************************************************************************/ +void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + p_cb->local_keypress_notification = *(UINT8 *) p_data; + smp_send_cmd(SMP_OPCODE_PAIR_KEYPR_NOTIF, p_cb); +} + +/******************************************************************************* +** Function smp_send_enc_info +** Description send encryption information command. +*******************************************************************************/ +void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_LENC_KEYS le_key; + + SMP_TRACE_DEBUG("%s p_cb->loc_enc_size = %d\n", __func__, p_cb->loc_enc_size); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + + smp_send_cmd(SMP_OPCODE_ENCRYPT_INFO, p_cb); + smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb); + + /* save the DIV and key size information when acting as slave device */ + memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + le_key.div = p_cb->div; + le_key.key_size = p_cb->loc_enc_size; + le_key.sec_level = p_cb->sec_level; + +#if (BLE_INCLUDED == TRUE) + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + } + + SMP_TRACE_DEBUG ("%s\n", __func__); + + smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE +} + +/******************************************************************************* +** Function smp_send_id_info +** Description send ID information command. +*******************************************************************************/ +void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, FALSE); + + smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb); + smp_send_cmd(SMP_OPCODE_ID_ADDR, p_cb); + +#if (BLE_INCLUDED == TRUE) + tBTM_LE_KEY_VALUE le_key; + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LID, + &le_key, TRUE); + } +#endif ///BLE_INCLUDED == TRUE + + smp_key_distribution_by_transport(p_cb, NULL); +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_send_csrk_info +** Description send CSRK command. +*******************************************************************************/ +void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_LCSRK_KEYS key; + SMP_TRACE_DEBUG("%s\n", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, FALSE); + + if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb)) { + key.div = p_cb->div; + key.sec_level = p_cb->sec_level; + key.counter = 0; /* initialize the local counter */ + memcpy (key.csrk, p_cb->csrk, BT_OCTET16_LEN); + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, (tBTM_LE_KEY_VALUE *)&key, TRUE); + } + + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_send_ltk_reply +** Description send LTK reply +*******************************************************************************/ +void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + /* send stk as LTK response */ + btm_ble_ltk_request_reply(p_cb->pairing_bda, TRUE, p_data->key.p_data); +} + +/******************************************************************************* +** Function smp_proc_sec_req +** Description process security request. +*******************************************************************************/ +void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ *)p_data; + tBTM_BLE_SEC_REQ_ACT sec_req_act; + UINT8 reason; + + SMP_TRACE_DEBUG("%s auth_req=0x%x", __func__, auth_req); + + p_cb->cb_evt = 0; + btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act); + + SMP_TRACE_DEBUG("%s sec_req_act=0x%x", __func__, sec_req_act); + + switch (sec_req_act) { + case BTM_BLE_SEC_REQ_ACT_ENCRYPT: + SMP_TRACE_DEBUG("%s BTM_BLE_SEC_REQ_ACT_ENCRYPT", __func__); + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + break; + + case BTM_BLE_SEC_REQ_ACT_PAIR: + p_cb->secure_connections_only_mode_required = + (btm_cb.security_mode == BTM_SEC_MODE_SC) ? TRUE : FALSE; + + /* respond to non SC pairing request as failure in SC only mode */ + if (p_cb->secure_connections_only_mode_required && + (auth_req & SMP_SC_SUPPORT_BIT) == 0) { + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } else { + /* initialize local i/r key to be default keys */ + p_cb->peer_auth_req = auth_req; + p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY ; + p_cb->cb_evt = SMP_SEC_REQUEST_EVT; + } + break; + + case BTM_BLE_SEC_REQ_ACT_DISCARD: + p_cb->discard_sec_req = TRUE; + break; + + default: + /* do nothing */ + break; + } +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_proc_sec_grant +** Description process security grant. +*******************************************************************************/ +void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 res = *(UINT8 *)p_data; + SMP_TRACE_DEBUG("%s", __func__); + if (res != SMP_SUCCESS) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data); + } else { /*otherwise, start pairing */ + /* send IO request callback */ + p_cb->cb_evt = SMP_IO_CAP_REQ_EVT; + } +} + +/******************************************************************************* +** Function smp_proc_pair_fail +** Description process pairing failure from peer device +*******************************************************************************/ +void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + p_cb->status = *(UINT8 *)p_data; +} + +/******************************************************************************* +** Function smp_get_auth_mode +** Description Get the SMP pairing auth mode +*******************************************************************************/ +uint16_t smp_get_auth_mode (tSMP_ASSO_MODEL model) +{ + SMP_TRACE_DEBUG("%s model %d", __func__, model); + uint16_t auth = 0; + if (model == SMP_MODEL_ENCRYPTION_ONLY || model == SMP_MODEL_SEC_CONN_JUSTWORKS) { + //No MITM + if(model == SMP_MODEL_SEC_CONN_JUSTWORKS) { + //SC SMP_SC_SUPPORT_BIT + auth |= SMP_SC_SUPPORT_BIT; + } + } else if (model <= SMP_MODEL_KEY_NOTIF) { + //NO SC, MITM + auth |= SMP_AUTH_YN_BIT; + } else if (model <= SMP_MODEL_SEC_CONN_OOB) { + //SC, MITM + auth |= SMP_SC_SUPPORT_BIT; + auth |= SMP_AUTH_YN_BIT; + } else { + auth = 0; + } + return auth; +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_proc_pair_cmd +** Description Process the SMP pairing request/response from peer device +*******************************************************************************/ +void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_ENC_KEY_SIZE; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + + SMP_TRACE_DEBUG("%s\n", __func__); + /* erase all keys if it is slave proc pairing req*/ + if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) { + btm_sec_clear_ble_keys(p_dev_rec); + } + + p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR; + + STREAM_TO_UINT8(p_cb->peer_io_caps, p); + STREAM_TO_UINT8(p_cb->peer_oob_flag, p); + STREAM_TO_UINT8(p_cb->peer_auth_req, p); + STREAM_TO_UINT8(p_cb->peer_enc_size, p); + STREAM_TO_UINT8(p_cb->peer_i_key, p); + STREAM_TO_UINT8(p_cb->peer_r_key, p); + + if (smp_command_has_invalid_parameters(p_cb)) { + reason = SMP_INVALID_PARAMETERS; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + p_cb->accept_specified_sec_auth = bta_dm_co_ble_get_accept_auth_enable(); + p_cb->origin_loc_auth_req = bta_dm_co_ble_get_auth_req(); + if (p_cb->role == HCI_ROLE_SLAVE) { + if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { + /* peer (master) started pairing sending Pairing Request */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + p_cb->cb_evt = SMP_SEC_REQUEST_EVT; + } else { /* update local i/r key according to pairing request */ + /* pairing started with this side (slave) sending Security Request */ + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { + SMP_TRACE_ERROR("%s pairing failed - slave requires secure connection only mode", + __func__); + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model); + if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) { + auth |= SMP_AUTH_GEN_BOND; + } + p_cb->auth_mode = auth; + if (p_cb->accept_specified_sec_auth) { + if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) { + SMP_TRACE_ERROR("%s pairing failed - slave requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x", + __func__, p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req); + if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) { + btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE); + } + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB && p_cb->loc_oob_flag == SMP_OOB_PRESENT) { + if (smp_request_oob_data(p_cb)) { + return; + } + } else { + smp_send_pair_rsp(p_cb, NULL); + } + } + } else { /* Master receives pairing response */ + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { + SMP_TRACE_ERROR ("Master requires secure connection only mode \ + but it can't be provided -> Master fails pairing"); + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model); + if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) { + auth |= SMP_AUTH_GEN_BOND; + } + p_cb->auth_mode = auth; + if (p_cb->accept_specified_sec_auth) { + if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) { + SMP_TRACE_ERROR("%s pairing failed - master requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x", + __func__, p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req); + if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) { + btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE); + } + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + } + + /* Only if peer oob data present, then should request peer oob data */ + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB && p_cb->loc_oob_flag == SMP_OOB_PRESENT) { + if (smp_request_oob_data(p_cb)) { + return; + } + } else { + smp_decide_association_model(p_cb, NULL); + } + } +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_proc_confirm +** Description process pairing confirm from peer device +*******************************************************************************/ +void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) { + /* save the SConfirm for comparison later */ + STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN); + } + + p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM; +} + +#if 0 //Unused +/******************************************************************************* +** Function smp_proc_init +** Description process pairing initializer from peer device +*******************************************************************************/ +void smp_proc_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + /* save the SRand for comparison */ + STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN); +} +#endif + +/******************************************************************************* +** Function smp_proc_rand +** Description process pairing random (nonce) from peer device +*******************************************************************************/ +void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + /* save the SRand for comparison */ + STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN); +} + +/******************************************************************************* +** Function smp_process_pairing_public_key +** Description process pairing public key command from the peer device +** - saves the peer public key; +** - sets the flag indicating that the peer public key is received; +** - calls smp_wait_for_both_public_keys(...). +** +*******************************************************************************/ +void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN); + STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN); + + /* Check if the peer device's and own public key are not same. If they are same then + * return pairing fail. This check is needed to avoid 'Impersonation in Passkey entry + * protocol' vulnerability (CVE-2020-26558).*/ + if ((memcmp(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, sizeof(BT_OCTET32)) == 0)) { + p_cb->status = SMP_PAIR_AUTH_FAIL; + p_cb->failure = SMP_PAIR_AUTH_FAIL; + reason = SMP_PAIR_AUTH_FAIL; + SMP_TRACE_ERROR("%s, Peer and own device cannot have same public key.", __func__); + smp_sm_event(p_cb, SMP_PAIRING_FAILED_EVT, &reason); + return ; + } + /* In order to prevent the x and y coordinates of the public key from being modified, + we need to check whether the x and y coordinates are on the given elliptic curve. */ + if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) { + SMP_TRACE_ERROR("%s, Invalid Public key.", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY; + + smp_wait_for_both_public_keys(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_process_pairing_commitment +** Description process pairing commitment from peer device +*******************************************************************************/ +void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_COMM; + + if (p != NULL) { + STREAM_TO_ARRAY(p_cb->remote_commitment, p, BT_OCTET16_LEN); + } +} + +/******************************************************************************* +** Function smp_process_dhkey_check +** Description process DHKey Check from peer device +*******************************************************************************/ +void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) { + STREAM_TO_ARRAY(p_cb->remote_dhkey_check, p, BT_OCTET16_LEN); + } + + p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK; +} + +/******************************************************************************* +** Function smp_process_keypress_notification +** Description process pairing keypress notification from peer device +*******************************************************************************/ +void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_INVALID_PARAMETERS; + + SMP_TRACE_DEBUG("%s", __func__); + p_cb->status = *(UINT8 *)p_data; + + if (smp_command_has_invalid_parameters(p_cb)) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p != NULL) { + STREAM_TO_UINT8(p_cb->peer_keypress_notification, p); + } else { + p_cb->peer_keypress_notification = BTM_SP_KEY_OUT_OF_RANGE; + } + p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT; +} + +#if (CLASSIC_BT_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_br_process_pairing_command +** Description Process the SMP pairing request/response from peer device via +** BR/EDR transport. +*******************************************************************************/ +void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + UINT8 reason = SMP_ENC_KEY_SIZE; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda); + + SMP_TRACE_DEBUG("%s", __func__); + /* rejecting BR pairing request over non-SC BR link */ + if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) { + reason = SMP_XTRANS_DERIVE_NOT_ALLOW; + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + return; + } + +#if (BLE_INCLUDED == TRUE) + /* erase all keys if it is slave proc pairing req*/ + if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) { + btm_sec_clear_ble_keys(p_dev_rec); + } +#endif ///BLE_INCLUDED == TRUE + + p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR; + + STREAM_TO_UINT8(p_cb->peer_io_caps, p); + STREAM_TO_UINT8(p_cb->peer_oob_flag, p); + STREAM_TO_UINT8(p_cb->peer_auth_req, p); + STREAM_TO_UINT8(p_cb->peer_enc_size, p); + STREAM_TO_UINT8(p_cb->peer_i_key, p); + STREAM_TO_UINT8(p_cb->peer_r_key, p); + + if (smp_command_has_invalid_parameters(p_cb)) { + reason = SMP_INVALID_PARAMETERS; + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + return; + } + + /* peer (master) started pairing sending Pairing Request */ + /* or being master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + if (p_cb->role == HCI_ROLE_SLAVE) { + p_dev_rec->new_encryption_key_is_p256 = FALSE; + /* shortcut to skip Security Grant step */ + p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; + } else { /* Master receives pairing response */ + SMP_TRACE_DEBUG("%s master rcvs valid PAIRING RESPONSE." + " Supposed to move to key distribution phase. ", __func__); + } + + /* auth_req received via BR/EDR SM channel is set to 0, + but everything derived/exchanged has to be saved */ + p_cb->peer_auth_req |= SMP_AUTH_BOND; + p_cb->loc_auth_req |= SMP_AUTH_BOND; +} + +/******************************************************************************* +** Function smp_br_process_security_grant +** Description process security grant in case of pairing over BR/EDR transport. +*******************************************************************************/ +void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 res = *(UINT8 *)p_data; + SMP_TRACE_DEBUG("%s", __func__); + if (res != SMP_SUCCESS) { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, p_data); + } else { /*otherwise, start pairing */ + /* send IO request callback */ + p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; + } +} + +/******************************************************************************* +** Function smp_br_check_authorization_request +** Description sets the SMP kes to be derived/distribute over BR/EDR transport +** before starting the distribution/derivation +*******************************************************************************/ +void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + + SMP_TRACE_DEBUG("%s rcvs i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key, + p_cb->local_r_key); + + /* In LE SC mode LK field is ignored when BR/EDR transport is used */ + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + + /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer. + ** Set local_r_key on master to expect only these keys. */ + if (p_cb->role == HCI_ROLE_MASTER) { + p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK); + } + + SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key, + p_cb->local_r_key); + + if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) || + (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/ + (p_cb->local_i_key || p_cb->local_r_key)) { + smp_br_state_machine_event(p_cb, SMP_BR_BOND_REQ_EVT, NULL); + + /* if no peer key is expected, start master key distribution */ + if (p_cb->role == HCI_ROLE_MASTER && p_cb->local_r_key == 0) { + smp_key_distribution_by_transport(p_cb, NULL); + } + } else { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + } +} + +/******************************************************************************* +** Function smp_br_select_next_key +** Description selects the next key to derive/send when BR/EDR transport is +** used. +*******************************************************************************/ +void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x", + __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key); + + if (p_cb->role == HCI_ROLE_SLAVE || + (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) { + smp_key_pick_key(p_cb, p_data); + } + + if (!p_cb->local_i_key && !p_cb->local_r_key) { + /* state check to prevent re-entrance */ + if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) { + if (p_cb->total_tx_unacked == 0) { + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); + } else { + p_cb->wait_for_authorization_complete = TRUE; + } + } + } +} +#endif ///CLASSIC_BT_INCLUDED == TRUE + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_proc_enc_info +** Description process encryption information from peer device +*******************************************************************************/ +void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s\n", __func__); + STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN); + + smp_key_distribution(p_cb, NULL); +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_proc_master_id +** Description process master ID from slave device +*******************************************************************************/ +void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + tBTM_LE_PENC_KEYS le_key; + + SMP_TRACE_DEBUG("%s\np_cb->peer_auth_req = %d,p_cb->loc_auth_req= %d\n", __func__, + p_cb->peer_auth_req, p_cb->loc_auth_req); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, TRUE); + + STREAM_TO_UINT16(le_key.ediv, p); + STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN ); + + /* store the encryption keys from peer device */ + memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + le_key.sec_level = p_cb->sec_level; + le_key.key_size = p_cb->loc_enc_size; + +#if (BLE_INCLUDED == TRUE) + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, + BTM_LE_KEY_PENC, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + } + + smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE +} + +/******************************************************************************* +** Function smp_proc_enc_info +** Description process identity information from peer device +*******************************************************************************/ +void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + + SMP_TRACE_DEBUG("%s", __func__); + STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */ + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_id_addr +** Description process identity address from peer device +*******************************************************************************/ +void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = (UINT8 *)p_data; + tBTM_LE_PID_KEYS pid_key; + + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, TRUE); + + STREAM_TO_UINT8(pid_key.addr_type, p); + STREAM_TO_BDADDR(pid_key.static_addr, p); + memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN); + + /* to use as BD_ADDR for lk derived from ltk */ + p_cb->id_addr_rcvd = TRUE; + p_cb->id_addr_type = pid_key.addr_type; + memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN); + +#if (BLE_INCLUDED == TRUE) + /* store the ID key from peer device */ + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, + (tBTM_LE_KEY_VALUE *)&pid_key, TRUE); + } +#endif ///BLE_INCLUDED == TRUE + + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_srk_info +** Description process security information from peer device +*******************************************************************************/ +void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ +#if (BLE_INCLUDED == TRUE) + tBTM_LE_PCSRK_KEYS le_key; + + SMP_TRACE_DEBUG("%s", __func__); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, TRUE); + + /* save CSRK to security record */ + le_key.sec_level = p_cb->sec_level; + memcpy (le_key.csrk, p_data, BT_OCTET16_LEN); /* get peer CSRK */ + le_key.counter = 0; /* initialize the peer counter */ + + if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) { + btm_sec_save_le_key(p_cb->pairing_bda, + BTM_LE_KEY_PCSRK, + (tBTM_LE_KEY_VALUE *)&le_key, TRUE); + } + +#endif ///BLE_INCLUDED == TRUE + smp_key_distribution_by_transport(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_proc_compare +** Description process compare value +*******************************************************************************/ +void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) { + /* compare the max encryption key size, and save the smaller one for the link */ + if ( p_cb->peer_enc_size < p_cb->loc_enc_size) { + p_cb->loc_enc_size = p_cb->peer_enc_size; + } + + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_sm_event(p_cb, SMP_RAND_EVT, NULL); + } else { + /* master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + } + + } else { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_proc_sl_key +** Description process key ready events. +*******************************************************************************/ +void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 key_type = p_data->key.key_type; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (key_type == SMP_KEY_TYPE_TK) { + smp_generate_srand_mrand_confirm(p_cb, NULL); + } else if (key_type == SMP_KEY_TYPE_CFM) { + smp_set_state(SMP_STATE_WAIT_CONFIRM); + + if (p_cb->flags & SMP_PAIR_FLAGS_CMD_CONFIRM) { + smp_sm_event(p_cb, SMP_CONFIRM_EVT, NULL); + } + } +} + +/******************************************************************************* +** Function smp_start_enc +** Description start encryption +*******************************************************************************/ +void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tBTM_STATUS cmd; + UINT8 reason = SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (p_data != NULL) { + cmd = btm_ble_start_encrypt(p_cb->pairing_bda, TRUE, p_data->key.p_data); + } else { + cmd = btm_ble_start_encrypt(p_cb->pairing_bda, FALSE, NULL); + } + + if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_proc_discard +** Description processing for discard security request +*******************************************************************************/ +void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { + smp_reset_control_value(p_cb); + } +} + +/******************************************************************************* +** Function smp_enc_cmpl +** Description encryption success +*******************************************************************************/ +void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 enc_enable = *(UINT8 *)p_data; + UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s\n", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); +} + +/******************************************************************************* +** Function smp_check_auth_req +** Description check authentication request +*******************************************************************************/ +void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 enc_enable = *(UINT8 *)p_data; + UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL; + + SMP_TRACE_DEBUG("%s rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)\n", + __func__, enc_enable, p_cb->local_i_key, p_cb->local_r_key); + if (enc_enable == 1) { + if (p_cb->le_secure_connections_mode_is_used) { + /* In LE SC mode LTK is used instead of STK and has to be always saved */ + p_cb->local_i_key |= SMP_SEC_KEY_TYPE_ENC; + p_cb->local_r_key |= SMP_SEC_KEY_TYPE_ENC; + + /* In LE SC mode LK is derived from LTK only if both sides request it */ + if (!(p_cb->local_i_key & SMP_SEC_KEY_TYPE_LK) || + !(p_cb->local_r_key & SMP_SEC_KEY_TYPE_LK)) { + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + + /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer. + ** Set local_r_key on master to expect only these keys. + */ + if (p_cb->role == HCI_ROLE_MASTER) { + p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK); + } + } else { + /* in legacy mode derivation of BR/EDR LK is not supported */ + p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK; + p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK; + } + SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x " + "(i-initiator r-responder)\n", + __func__, p_cb->local_i_key, p_cb->local_r_key); + + if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) || + (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/ + (p_cb->local_i_key || p_cb->local_r_key)) { + smp_sm_event(p_cb, SMP_BOND_REQ_EVT, NULL); + } else { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + } else if (enc_enable == 0) { + /* if failed for encryption after pairing, send callback */ + if (p_cb->flags & SMP_PAIR_FLAG_ENC_AFTER_PAIR) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + /* if enc failed for old security information */ + /* if master device, clean up and abck to idle; slave device do nothing */ + else if (p_cb->role == HCI_ROLE_MASTER) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } + } +} + +/******************************************************************************* +** Function smp_key_pick_key +** Description Pick a key distribution function based on the key mask. +*******************************************************************************/ +void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 key_to_dist = (p_cb->role == HCI_ROLE_SLAVE) ? p_cb->local_r_key : p_cb->local_i_key; + UINT8 i = 0; + + SMP_TRACE_DEBUG("%s key_to_dist=0x%x\n", __func__, key_to_dist); + while (i < SMP_KEY_DIST_TYPE_MAX) { + SMP_TRACE_DEBUG("key to send = %02x, i = %d\n", key_to_dist, i); + + if (key_to_dist & (1 << i) && smp_distribute_act[i] != NULL) { + SMP_TRACE_DEBUG("smp_distribute_act[%d]\n", i); + (* smp_distribute_act[i])(p_cb, p_data); + break; + } + i ++; + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_key_distribution +** Description start key distribution if required. +*******************************************************************************/ +void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_SUCCESS; + SMP_TRACE_DEBUG("\n%s role=%d (0-master) r_keys=0x%x i_keys=0x%x\n", + __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key); + + if (p_cb->role == HCI_ROLE_SLAVE || + (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) { + smp_key_pick_key(p_cb, p_data); + } + + if (!p_cb->local_i_key && !p_cb->local_r_key) { + /* state check to prevent re-entrant */ + if (smp_get_state() == SMP_STATE_BOND_PENDING) { + if (p_cb->derive_lk) { + smp_derive_link_key_from_long_term_key(p_cb, NULL); + p_cb->derive_lk = FALSE; + } + + if (p_cb->total_tx_unacked == 0) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } else { + p_cb->wait_for_authorization_complete = TRUE; + } + } + } +} + +/******************************************************************************* +** Function smp_decide_association_model +** Description This function is called to select assoc model to be used for +** STK generation and to start STK generation process. +** +*******************************************************************************/ +void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 failure = SMP_UNKNOWN_IO_CAP; + UINT8 int_evt = 0; + tSMP_KEY key; + tSMP_INT_DATA *p = NULL; + + SMP_TRACE_DEBUG("%s Association Model = %d\n", __func__, p_cb->selected_association_model); + + switch (p_cb->selected_association_model) { + case SMP_MODEL_ENCRYPTION_ONLY: /* TK = 0, go calculate Confirm */ + p_cb->sec_level = SMP_SEC_UNAUTHENTICATE; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) \n", p_cb->sec_level ); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = p_cb->tk; + p = (tSMP_INT_DATA *)&key; + + memset(p_cb->tk, 0, BT_OCTET16_LEN); + /* TK, ready */ + int_evt = SMP_KEY_READY_EVT; + break; + + case SMP_MODEL_PASSKEY: + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) \n", p_cb->sec_level ); + + p_cb->cb_evt = SMP_PASSKEY_REQ_EVT; + int_evt = SMP_TK_REQ_EVT; + break; + + case SMP_MODEL_OOB: + SMP_TRACE_ERROR ("Association Model = SMP_MODEL_OOB\n"); + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) \n", p_cb->sec_level ); + + p_cb->cb_evt = SMP_OOB_REQ_EVT; + int_evt = SMP_TK_REQ_EVT; + break; + + case SMP_MODEL_KEY_NOTIF: + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_DEBUG("Need to generate Passkey\n"); + + /* generate passkey and notify application */ + smp_generate_passkey(p_cb, NULL); + break; + + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + case SMP_MODEL_SEC_CONN_OOB: + int_evt = SMP_PUBL_KEY_EXCH_REQ_EVT; + break; + + case SMP_MODEL_OUT_OF_RANGE: + SMP_TRACE_ERROR("Association Model = SMP_MODEL_OUT_OF_RANGE (failed)\n"); + p = (tSMP_INT_DATA *)&failure; + int_evt = SMP_AUTH_CMPL_EVT; + break; + + default: + SMP_TRACE_ERROR("Association Model = %d (SOMETHING IS WRONG WITH THE CODE)\n", + p_cb->selected_association_model); + p = (tSMP_INT_DATA *)&failure; + int_evt = SMP_AUTH_CMPL_EVT; + } + + SMP_TRACE_EVENT ("sec_level=%d \n", p_cb->sec_level ); + if (int_evt) { + smp_sm_event(p_cb, int_evt, p); + } +} + +/******************************************************************************* +** Function smp_process_io_response +** Description process IO response for a slave device. +*******************************************************************************/ +void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + uint8_t reason = SMP_PAIR_AUTH_FAIL; + SMP_TRACE_DEBUG("%s\n", __func__); + if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { + /* pairing started by local (slave) Security Request */ + smp_set_state(SMP_STATE_SEC_REQ_PENDING); + smp_send_cmd(SMP_OPCODE_SEC_REQ, p_cb); + } else { /* plan to send pairing respond */ + /* pairing started by peer (master) Pairing Request */ + p_cb->selected_association_model = smp_select_association_model(p_cb); + + if (p_cb->secure_connections_only_mode_required && + (!(p_cb->le_secure_connections_mode_is_used) || + (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) { + SMP_TRACE_ERROR ("Slave requires secure connection only mode \ + but it can't be provided -> Slave fails pairing\n"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model); + if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) { + auth |= SMP_AUTH_GEN_BOND; + } + p_cb->auth_mode = auth; + if (p_cb->accept_specified_sec_auth) { + if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) { + SMP_TRACE_ERROR("pairing failed - slave requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x", + p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req); + if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) { + btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE); + } + reason = SMP_PAIR_AUTH_FAIL; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB && p_cb->loc_oob_flag == SMP_OOB_PRESENT) { + if (smp_request_oob_data(p_cb)) { + return; + } + } + smp_send_pair_rsp(p_cb, NULL); + } +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_br_process_slave_keys_response +** Description process application keys response for a slave device +** (BR/EDR transport). +*******************************************************************************/ +void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + smp_br_send_pair_response(p_cb, NULL); +} + +/******************************************************************************* +** Function smp_br_send_pair_response +** Description actions related to sending pairing response over BR/EDR transport. +*******************************************************************************/ +void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + p_cb->local_i_key &= p_cb->peer_i_key; + p_cb->local_r_key &= p_cb->peer_r_key; + + smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb); +} + +/******************************************************************************* +** Function smp_pairing_cmpl +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + if (p_cb->total_tx_unacked == 0) { + /* process the pairing complete */ + smp_proc_pairing_cmpl(p_cb); + } +} + +/******************************************************************************* +** Function smp_pair_terminate +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + p_cb->status = SMP_CONN_TOUT; + smp_proc_pairing_cmpl(p_cb); +} + +/******************************************************************************* +** Function smp_idle_terminate +** Description This function calledin idle state to determine to send authentication +** complete or not. +*******************************************************************************/ +void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { + SMP_TRACE_DEBUG("Pairing terminated at IDLE state.\n"); + p_cb->status = SMP_FAIL; + smp_proc_pairing_cmpl(p_cb); + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_fast_conn_param +** Description apply default connection parameter for pairing process +*******************************************************************************/ +void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + if(p_cb->role == BTM_ROLE_MASTER) { +#if (BT_MULTI_CONNECTION_ENBALE == FALSE) + L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE); +#endif + } else { +#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE) + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda); + if(p_rec && p_rec->ble.skip_update_conn_param) { + //do nothing + return; + } + /* Disable L2CAP connection parameter updates while bonding since + some peripherals are not able to revert to fast connection parameters + during the start of service discovery. Connection paramter updates + get enabled again once service discovery completes. */ + #if (BT_MULTI_CONNECTION_ENBALE == FALSE) + L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE); + #endif +#endif + } +} + +/******************************************************************************* +** Function smp_both_have_public_keys +** Description The function is called when both local and peer public keys are +** saved. +** Actions: +** - invokes DHKey computation; +** - on slave side invokes sending local public key to the peer. +** - invokes SC phase 1 process. +*******************************************************************************/ +void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + /* invokes DHKey computation */ + smp_compute_dhkey(p_cb); + + /* on slave side invokes sending local public key to the peer */ + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_send_pair_public_key(p_cb, NULL); + } + + smp_sm_event(p_cb, SMP_SC_DHKEY_CMPLT_EVT, NULL); +} + +/******************************************************************************* +** Function smp_start_secure_connection_phase1 +** Description The function starts Secure Connection phase1 i.e. invokes initialization of Secure Connection +** phase 1 parameters and starts building/sending to the peer +** messages appropriate for the role and association model. +*******************************************************************************/ +void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) { + p_cb->sec_level = SMP_SEC_UNAUTHENTICATE; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE)\n ", p_cb->sec_level ); + } else { + p_cb->sec_level = SMP_SEC_AUTHENTICATED; + SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED)\n ", p_cb->sec_level ); + } + + switch (p_cb->selected_association_model) { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + memset(p_cb->local_random, 0, BT_OCTET16_LEN); + smp_start_nonce_generation(p_cb); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + /* user has to provide passkey */ + p_cb->cb_evt = SMP_PASSKEY_REQ_EVT; + smp_sm_event(p_cb, SMP_TK_REQ_EVT, NULL); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + /* passkey has to be provided to user */ + SMP_TRACE_DEBUG("Need to generate SC Passkey\n"); + smp_generate_passkey(p_cb, NULL); + break; + case SMP_MODEL_SEC_CONN_OOB: + /* use the available OOB information */ + smp_process_secure_connection_oob_data(p_cb, NULL); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n", + p_cb->selected_association_model); + break; + } +} + +/******************************************************************************* +** Function smp_process_local_nonce +** Description The function processes new local nonce. +** +** Note It is supposed to be called in SC phase1. +*******************************************************************************/ +void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + switch (p_cb->selected_association_model) { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + if (p_cb->role == HCI_ROLE_SLAVE) { + /* slave calculates and sends local commitment */ + smp_calculate_local_commitment(p_cb); + smp_send_commitment(p_cb, NULL); + /* slave has to wait for peer nonce */ + smp_set_state(SMP_STATE_WAIT_NONCE); + } else { /* i.e. master */ + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) { + /* slave commitment is already received, send local nonce, wait for remote nonce*/ + SMP_TRACE_DEBUG("master in assoc mode = %d \ + already rcvd slave commitment - race condition\n", + p_cb->selected_association_model); + p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM; + smp_send_rand(p_cb, NULL); + smp_set_state(SMP_STATE_WAIT_NONCE); + } + } + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + smp_calculate_local_commitment(p_cb); + + if (p_cb->role == HCI_ROLE_MASTER) { + smp_send_commitment(p_cb, NULL); + } else { /* slave */ + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) { + /* master commitment is already received */ + smp_send_commitment(p_cb, NULL); + smp_set_state(SMP_STATE_WAIT_NONCE); + } + } + break; + case SMP_MODEL_SEC_CONN_OOB: + if (p_cb->role == HCI_ROLE_MASTER) { + smp_send_rand(p_cb, NULL); + } + + smp_set_state(SMP_STATE_WAIT_NONCE); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n", + p_cb->selected_association_model); + break; + } +} + +/******************************************************************************* +** Function smp_process_peer_nonce +** Description The function processes newly received and saved in CB peer nonce. +** The actions depend on the selected association model and the role. +** +** Note It is supposed to be called in SC phase1. +*******************************************************************************/ +void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason; + + SMP_TRACE_DEBUG("%s start \n", __func__); + + switch (p_cb->selected_association_model) { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + /* in these models only master receives commitment */ + if (p_cb->role == HCI_ROLE_MASTER) { + if (!smp_check_commitment(p_cb)) { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + break; + } + } else { + /* slave sends local nonce */ + smp_send_rand(p_cb, NULL); + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) { + /* go directly to phase 2 */ + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + } else { /* numeric comparison */ + smp_set_state(SMP_STATE_WAIT_NONCE); + smp_sm_event(p_cb, SMP_SC_CALC_NC_EVT, NULL); + } + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + if (!smp_check_commitment(p_cb)) { + reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + break; + } + + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_send_rand(p_cb, NULL); + } + + if (++p_cb->round < 20) { + smp_set_state(SMP_STATE_SEC_CONN_PHS1_START); + p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM; + smp_start_nonce_generation(p_cb); + break; + } + + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + break; + case SMP_MODEL_SEC_CONN_OOB: + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_send_rand(p_cb, NULL); + } + + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); + break; + default: + SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n", + p_cb->selected_association_model); + break; + } + + SMP_TRACE_DEBUG("%s end\n ", __FUNCTION__); +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_match_dhkey_checks +** Description checks if the calculated peer DHKey Check value is the same as +** received from the peer DHKey check value. +*******************************************************************************/ +void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 reason = SMP_DHKEY_CHK_FAIL; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN)) { + SMP_TRACE_WARNING ("dhkey checks do no match\n"); + p_cb->failure = reason; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + SMP_TRACE_EVENT ("dhkey checks match\n"); + + /* compare the max encryption key size, and save the smaller one for the link */ + if (p_cb->peer_enc_size < p_cb->loc_enc_size) { + p_cb->loc_enc_size = p_cb->peer_enc_size; + } + + if (p_cb->role == HCI_ROLE_SLAVE) { + smp_sm_event(p_cb, SMP_PAIR_DHKEY_CHCK_EVT, NULL); + } else { + /* master device always use received i/r key as keys to distribute */ + p_cb->local_i_key = p_cb->peer_i_key; + p_cb->local_r_key = p_cb->peer_r_key; + smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL); + } +} + +/******************************************************************************* +** Function smp_move_to_secure_connections_phase2 +** Description Signal State Machine to start SC phase 2 initialization (to +** compute local DHKey Check value). +** +** Note SM is supposed to be in the state SMP_STATE_SEC_CONN_PHS2_START. +*******************************************************************************/ +void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL); +} + +/******************************************************************************* +** Function smp_phase_2_dhkey_checks_are_present +** Description generates event if dhkey check from the peer is already received. +** +** Note It is supposed to be used on slave to prevent race condition. +** It is supposed to be called after slave dhkey check is calculated. +*******************************************************************************/ +void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK) { + smp_sm_event(p_cb, SMP_SC_2_DHCK_CHKS_PRES_EVT, NULL); + } +} + +/******************************************************************************* +** Function smp_wait_for_both_public_keys +** Description generates SMP_BOTH_PUBL_KEYS_RCVD_EVT event when both local and master +** public keys are available. +** +** Note on the slave it is used to prevent race condition. +** +*******************************************************************************/ +void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if ((p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY) && + (p_cb->flags & SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY)) { + if ((p_cb->role == HCI_ROLE_SLAVE) && + ((p_cb->req_oob_type == SMP_OOB_LOCAL) || (p_cb->req_oob_type == SMP_OOB_BOTH))) { + smp_set_state(SMP_STATE_PUBLIC_KEY_EXCH); + } + smp_sm_event(p_cb, SMP_BOTH_PUBL_KEYS_RCVD_EVT, NULL); + } +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_start_passkey_verification +** Description Starts SC passkey entry verification. +*******************************************************************************/ +void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 *p = NULL; + + SMP_TRACE_DEBUG("%s\n", __func__); + p = p_cb->local_random; + UINT32_TO_STREAM(p, p_data->passkey); + + p = p_cb->peer_random; + UINT32_TO_STREAM(p, p_data->passkey); + + p_cb->round = 0; + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_process_secure_connection_oob_data +** Description Processes local/peer SC OOB data received from somewhere. +*******************************************************************************/ +void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + tSMP_SC_OOB_DATA *p_sc_oob_data = &p_cb->sc_oob_data; + if (p_sc_oob_data->loc_oob_data.present) { + memcpy(p_cb->local_random, p_sc_oob_data->loc_oob_data.randomizer, + sizeof(p_cb->local_random)); + } else { + SMP_TRACE_EVENT ("local OOB randomizer is absent\n"); + memset(p_cb->local_random, 0, sizeof (p_cb->local_random)); + } + + if (!p_sc_oob_data->peer_oob_data.present) { + SMP_TRACE_EVENT ("peer OOB data is absent\n"); + memset(p_cb->peer_random, 0, sizeof (p_cb->peer_random)); + } else { + memcpy(p_cb->peer_random, p_sc_oob_data->peer_oob_data.randomizer, + sizeof(p_cb->peer_random)); + memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment, + sizeof(p_cb->remote_commitment)); + + UINT8 reason = SMP_CONFIRM_VALUE_ERR; + /* check commitment */ + if (!smp_check_commitment(p_cb)) { + p_cb->failure = reason; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + if (p_cb->peer_oob_flag != SMP_OOB_PRESENT) { + /* the peer doesn't have local randomiser */ + SMP_TRACE_EVENT ("peer didn't receive local OOB data, set local randomizer to 0\n"); + memset(p_cb->local_random, 0, sizeof (p_cb->local_random)); + } + } + + print128(p_cb->local_random, (const UINT8 *)"local OOB randomizer"); + print128(p_cb->peer_random, (const UINT8 *)"peer OOB randomizer"); + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_set_local_oob_keys +** Description Saves calculated private/public keys in sc_oob_data.loc_oob_data, +** starts nonce generation +** (to be saved in sc_oob_data.loc_oob_data.randomizer). +*******************************************************************************/ +void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + memcpy(p_cb->sc_oob_data.loc_oob_data.private_key_used, p_cb->private_key, + BT_OCTET32_LEN); + p_cb->sc_oob_data.loc_oob_data.publ_key_used = p_cb->loc_publ_key; + smp_start_nonce_generation(p_cb); +} + +/******************************************************************************* +** Function smp_set_local_oob_random_commitment +** Description Saves calculated randomizer and commitment in sc_oob_data.loc_oob_data, +** passes sc_oob_data.loc_oob_data up for safekeeping. +*******************************************************************************/ +void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + memcpy(p_cb->sc_oob_data.loc_oob_data.randomizer, p_cb->rand, + BT_OCTET16_LEN); + + smp_calculate_f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x, + p_cb->sc_oob_data.loc_oob_data.publ_key_used.x, + p_cb->sc_oob_data.loc_oob_data.randomizer, 0, + p_cb->sc_oob_data.loc_oob_data.commitment); + + p_cb->sc_oob_data.loc_oob_data.present = true; +#if SMP_DEBUG == TRUE + UINT8 *p_print = NULL; + SMP_TRACE_DEBUG("local SC OOB data set:\n"); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.addr_sent_to; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"addr_sent_to", + sizeof(tBLE_BD_ADDR)); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.private_key_used; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"private_key_used", + BT_OCTET32_LEN); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.x; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"publ_key_used.x", + BT_OCTET32_LEN); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.y; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"publ_key_used.y", + BT_OCTET32_LEN); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.randomizer; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"randomizer", + BT_OCTET16_LEN); + p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.commitment; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *) "commitment", + BT_OCTET16_LEN); + SMP_TRACE_DEBUG(""); +#endif + + /* pass created OOB data up */ + p_cb->cb_evt = SMP_SC_LOC_OOB_DATA_UP_EVT; + smp_send_app_cback(p_cb, NULL); + + // Store the data for later use when we are paired with + smp_save_local_oob_data(p_cb); + + smp_cb_cleanup(p_cb); +} + +/******************************************************************************* +** +** Function smp_link_encrypted +** +** Description This function is called when link is encrypted and notified to +** slave device. Proceed to to send LTK, DIV and ER to master if +** bonding the devices. +** +** +** Returns void +** +*******************************************************************************/ +void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable) +{ + tSMP_CB *p_cb = &smp_cb; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); + SMP_TRACE_DEBUG("%s encr_enable=%d\n", __func__, encr_enable); + + if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0) { + /* encryption completed with STK, remmeber the key size now, could be overwite + * when key exchange happens */ + if (p_cb->loc_enc_size != 0 && encr_enable) { + /* update the link encryption key size if a SMP pairing just performed */ + btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size); + } + + smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable); + } else if (p_dev_rec && !p_dev_rec->role_master && !p_dev_rec->enc_init_by_we ){ + /* + if enc_init_by_we is false, it means that client initiates encryption before slave calls esp_ble_set_encryption() + we need initiate pairing_bda and p_cb->role then encryption, for example iPhones + */ + memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN); + p_cb->state = SMP_STATE_ENCRYPTION_PENDING; + p_cb->role = HCI_ROLE_SLAVE; + p_dev_rec->enc_init_by_we = FALSE; + smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable); + } else if (p_dev_rec && p_dev_rec->role_master && p_dev_rec->enc_init_by_we){ + memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN); + p_cb->state = SMP_STATE_ENCRYPTION_PENDING; + p_cb->role = HCI_ROLE_MASTER; + p_dev_rec->enc_init_by_we = FALSE; + smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable); + } +} + +/******************************************************************************* +** +** Function smp_proc_ltk_request +** +** Description This function is called when LTK request is received from +** controller. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN smp_proc_ltk_request(BD_ADDR bda) +{ + SMP_TRACE_DEBUG("%s state = %d\n", __func__, smp_cb.state); + BOOLEAN match = FALSE; + + if (!memcmp(bda, smp_cb.pairing_bda, BD_ADDR_LEN)) { + match = TRUE; + } else { + BD_ADDR dummy_bda = {0}; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bda); + if (p_dev_rec != NULL && + 0 == memcmp(p_dev_rec->ble.pseudo_addr, smp_cb.pairing_bda, BD_ADDR_LEN) && + 0 != memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN)) { + match = TRUE; + } + } + + if (match && smp_cb.state == SMP_STATE_ENCRYPTION_PENDING) { + smp_sm_event(&smp_cb, SMP_ENC_REQ_EVT, NULL); + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function smp_process_secure_connection_long_term_key +** +** Description This function is called to process SC LTK. +** SC LTK is calculated and used instead of STK. +** Here SC LTK is saved in BLE DB. +** +** Returns void +** +*******************************************************************************/ +void smp_process_secure_connection_long_term_key(void) +{ + tSMP_CB *p_cb = &smp_cb; + + SMP_TRACE_DEBUG("%s\n", __func__); + smp_save_secure_connections_long_term_key(p_cb); + + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + smp_key_distribution(p_cb, NULL); +} + +/******************************************************************************* +** +** Function smp_set_derive_link_key +** +** Description This function is called to set flag that indicates that +** BR/EDR LK has to be derived from LTK after all keys are +** distributed. +** +** Returns void +** +*******************************************************************************/ +void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG ("%s\n", __func__); + p_cb->derive_lk = TRUE; + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_LK, FALSE); + smp_key_distribution(p_cb, NULL); +} + +/******************************************************************************* +** +** Function smp_derive_link_key_from_long_term_key +** +** Description This function is called to derive BR/EDR LK from LTK. +** +** Returns void +** +*******************************************************************************/ +void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (!smp_calculate_link_key_from_long_term_key(p_cb)) { + SMP_TRACE_ERROR("%s failed\n", __FUNCTION__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + return; + } +} +#endif ///BLE_INCLUDED == TRUE + +#if (CLASSIC_BT_INCLUDED == TRUE) +/******************************************************************************* +** +** Function smp_br_process_link_key +** +** Description This function is called to process BR/EDR LK: +** - to derive SMP LTK from BR/EDR LK; +*8 - to save SMP LTK. +** +** Returns void +** +*******************************************************************************/ +void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG("%s\n", __func__); + if (!smp_calculate_long_term_key_from_link_key(p_cb)) { + SMP_TRACE_ERROR ("%s failed\n", __FUNCTION__); + smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); + return; + } + + SMP_TRACE_DEBUG("%s: LTK derivation from LK successfully completed\n", __FUNCTION__); + smp_save_secure_connections_long_term_key(p_cb); + smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE); + smp_br_select_next_key(p_cb, NULL); +} +#endif ///CLASSIC_BT_INCLUDED == TRUE + +/******************************************************************************* +** Function smp_key_distribution_by_transport +** Description depending on the transport used at the moment calls either +** smp_key_distribution(...) or smp_br_key_distribution(...). +*******************************************************************************/ +void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) + smp_br_select_next_key(p_cb, NULL); +#endif ///CLASSIC_BT_INCLUDED == TRUE + } else { +#if (BLE_INCLUDED == TRUE) + smp_key_distribution(p_cb, NULL); +#endif ///BLE_INCLUDED == TRUE + } +} + +/******************************************************************************* +** Function smp_br_pairing_complete +** Description This function is called to send the pairing complete callback +** and remove the connection if needed. +*******************************************************************************/ +void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->total_tx_unacked == 0) { + /* process the pairing complete */ + smp_proc_pairing_cmpl(p_cb); + } +} + +#endif diff --git a/lib/bt/host/bluedroid/stack/smp/smp_api.c b/lib/bt/host/bluedroid/stack/smp/smp_api.c new file mode 100644 index 00000000..78e295f4 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/smp_api.c @@ -0,0 +1,615 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the implementation of the SMP interface used by + * applications that can run over an SMP. + * + ******************************************************************************/ +#include <string.h> + +#include "common/bt_target.h" +//#include "bt_utils.h" +#if SMP_INCLUDED == TRUE +#include "smp_int.h" +#include "stack/smp_api.h" +#include "stack/l2cdefs.h" +#include "l2c_int.h" +#include "btm_int.h" +#include "stack/hcimsgs.h" + +#include "stack/btu.h" +#include "p_256_ecc_pp.h" +#include "osi/allocator.h" + +/******************************************************************************* +** +** Function SMP_Init +** +** Description This function initializes the SMP unit. +** +** Returns void +** +*******************************************************************************/ +void SMP_Init(void) +{ +#if SMP_DYNAMIC_MEMORY + smp_cb_ptr = (tSMP_CB *)osi_malloc(sizeof(tSMP_CB)); + curve_ptr = (elliptic_curve_t *)osi_malloc(sizeof(elliptic_curve_t)); + curve_p256_ptr = (elliptic_curve_t *)osi_malloc(sizeof(elliptic_curve_t)); +#endif + memset(&smp_cb, 0, sizeof(tSMP_CB)); + memset(&curve, 0, sizeof(elliptic_curve_t)); + memset(&curve_p256, 0, sizeof(elliptic_curve_t)); + +#if defined(SMP_INITIAL_TRACE_LEVEL) + smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL; +#else + smp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + SMP_TRACE_EVENT ("%s", __FUNCTION__); + + smp_l2cap_if_init(); + /* initialization of P-256 parameters */ + p_256_init_curve(KEY_LENGTH_DWORDS_P256); +} + +void SMP_Free(void) +{ + memset(&smp_cb, 0, sizeof(tSMP_CB)); +#if SMP_DYNAMIC_MEMORY + FREE_AND_RESET(smp_cb_ptr); + FREE_AND_RESET(curve_ptr); + FREE_AND_RESET(curve_p256_ptr); +#endif /* #if SMP_DYNAMIC_MEMORY */ +} + + +/******************************************************************************* +** +** Function SMP_SetTraceLevel +** +** Description This function sets the trace level for SMP. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Input Parameters: +** level: The level to set the GATT tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new or current trace level +** +*******************************************************************************/ +extern UINT8 SMP_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) { + smp_cb.trace_level = new_level; + } + + return (smp_cb.trace_level); +} + + +/******************************************************************************* +** +** Function SMP_Register +** +** Description This function register for the SMP services callback. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN SMP_Register (tSMP_CALLBACK *p_cback) +{ + SMP_TRACE_EVENT ("SMP_Register state=%d", smp_cb.state); + + if (smp_cb.p_callback != NULL) { + SMP_TRACE_WARNING ("SMP_Register: duplicate registration, overwrite it"); + } + smp_cb.p_callback = p_cback; + + return (TRUE); + +} + +/******************************************************************************* +** +** Function SMP_Pair +** +** Description This function call to perform a SMP pairing with peer device. +** Device support one SMP pairing at one time. +** +** Parameters bd_addr - peer device bd address. +** +** Returns None +** +*******************************************************************************/ +tSMP_STATUS SMP_Pair (BD_ADDR bd_addr) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 status = SMP_PAIR_INTERNAL_ERR; + + SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x \n", + __FUNCTION__, p_cb->state, p_cb->br_state, p_cb->flags); + if (p_cb->state != SMP_STATE_IDLE || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD || + p_cb->smp_over_br) { + /* pending security on going, reject this one */ + return SMP_BUSY; + } else { + p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD; + + memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN); + + if (!L2CA_ConnectFixedChnl (L2CAP_SMP_CID, bd_addr, BLE_ADDR_UNKNOWN_TYPE, FALSE)) { + SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.\n", __FUNCTION__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + return status; + } + + return SMP_STARTED; + } +} + +/******************************************************************************* +** +** Function SMP_BR_PairWith +** +** Description This function is called to start a SMP pairing over BR/EDR. +** Device support one SMP pairing at one time. +** +** Parameters bd_addr - peer device bd address. +** +** Returns SMP_STARTED if pairing started, otherwise reason for failure. +** +*******************************************************************************/ +#if (CLASSIC_BT_INCLUDED == TRUE) +tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 status = SMP_PAIR_INTERNAL_ERR; + + SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x ", + __func__, p_cb->state, p_cb->br_state, p_cb->flags); + + if (p_cb->state != SMP_STATE_IDLE || + p_cb->smp_over_br || + p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) { + /* pending security on going, reject this one */ + return SMP_BUSY; + } + + p_cb->role = HCI_ROLE_MASTER; + p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD; + p_cb->smp_over_br = TRUE; + + memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN); + + if (!L2CA_ConnectFixedChnl (L2CAP_SMP_BR_CID, bd_addr, BLE_ADDR_UNKNOWN_TYPE, FALSE)) { + SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __FUNCTION__); + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); + return status; + } + + return SMP_STARTED; +} +#endif ///CLASSIC_BT_INCLUDED == TRUE + +/******************************************************************************* +** +** Function SMP_PairCancel +** +** Description This function call to cancel a SMP pairing with peer device. +** +** Parameters bd_addr - peer device bd address. +** +** Returns TRUE - Pairining is cancelled +** +*******************************************************************************/ +BOOLEAN SMP_PairCancel (BD_ADDR bd_addr) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 err_code = SMP_PAIR_FAIL_UNKNOWN; + BOOLEAN status = FALSE; + + BTM_TRACE_EVENT ("SMP_CancelPair state=%d flag=0x%x ", p_cb->state, p_cb->flags); + if ( (p_cb->state != SMP_STATE_IDLE) && + (!memcmp (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN)) ) { + p_cb->is_pair_cancel = TRUE; + SMP_TRACE_DEBUG("Cancel Pairing: set fail reason Unknown"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &err_code); + status = TRUE; + } + + return status; +} +/******************************************************************************* +** +** Function SMP_SecurityGrant +** +** Description This function is called to grant security process. +** +** Parameters bd_addr - peer device bd address. +** res - result of the operation SMP_SUCCESS if success. +** Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts. +** +** Returns None +** +*******************************************************************************/ +void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res) +{ + SMP_TRACE_EVENT ("SMP_SecurityGrant "); + +#if (CLASSIC_BT_INCLUDED == TRUE) + if (smp_cb.smp_over_br) { + if (smp_cb.br_state != SMP_BR_STATE_WAIT_APP_RSP || + smp_cb.cb_evt != SMP_SEC_REQUEST_EVT || + memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) { + return; + } + + /* clear the SMP_SEC_REQUEST_EVT event after get grant */ + /* avoid generating duplicate pair request */ + smp_cb.cb_evt = 0; + smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT, &res); + return; + } +#endif ///CLASSIC_BT_INCLUDED == TRUE + + if (smp_cb.state != SMP_STATE_WAIT_APP_RSP || + smp_cb.cb_evt != SMP_SEC_REQUEST_EVT || + memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) { + return; + } + /* clear the SMP_SEC_REQUEST_EVT event after get grant */ + /* avoid generate duplicate pair request */ + smp_cb.cb_evt = 0; + smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &res); +} + +/******************************************************************************* +** +** Function SMP_PasskeyReply +** +** Description This function is called after Security Manager submitted +** passkey request to the application. +** +** Parameters: bd_addr - Address of the device for which passkey was requested +** res - result of the operation SMP_SUCCESS if success +** passkey - numeric value in the range of +** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)). +** +*******************************************************************************/ +void SMP_PasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey) +{ + tSMP_CB *p_cb = & smp_cb; + UINT8 failure = SMP_PASSKEY_ENTRY_FAIL; + + SMP_TRACE_EVENT ("SMP_PasskeyReply: Key: %d Result:%d", + passkey, res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT) { + SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong State: %d", p_cb->state); + return; + } + + if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) { + SMP_TRACE_ERROR ("SMP_PasskeyReply() - Wrong BD Addr"); + return; + } + + if (btm_find_dev (bd_addr) == NULL) { + SMP_TRACE_ERROR ("SMP_PasskeyReply() - no dev CB"); + return; + } + + if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS) { + SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail", passkey); + /* send pairing failure */ + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + + } else if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_ENT) { + smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &passkey); + } else { + smp_convert_string_to_tk(p_cb->tk, passkey); + } + + return; +} + +/******************************************************************************* +** +** Function SMP_SetStaticPasskey +** +** Description This function is called to set static passkey +** +** +** Parameters: add - set static passkey when add is TRUE +** clear static passkey when add is FALSE +** passkey - static passkey +** +** +*******************************************************************************/ +void SMP_SetStaticPasskey (BOOLEAN add, UINT32 passkey) +{ + SMP_TRACE_DEBUG("static passkey %6d", passkey); + tSMP_CB *p_cb = & smp_cb; + if(add) { + p_cb->static_passkey = passkey; + p_cb->use_static_passkey = true; + } else { + p_cb->static_passkey = 0; + p_cb->use_static_passkey = false; + } +} + +/******************************************************************************* +** +** Function SMP_ConfirmReply +** +** Description This function is called after Security Manager submitted +** numeric comparison request to the application. +** +** Parameters: bd_addr - Address of the device with which numeric +** comparison was requested +** res - comparison result SMP_SUCCESS if success +** +*******************************************************************************/ +void SMP_ConfirmReply (BD_ADDR bd_addr, UINT8 res) +{ + tSMP_CB *p_cb = & smp_cb; + UINT8 failure = SMP_NUMERIC_COMPAR_FAIL; + + SMP_TRACE_EVENT ("%s: Result:%d", __FUNCTION__, res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (p_cb->cb_evt != SMP_NC_REQ_EVT) { + SMP_TRACE_WARNING ("%s() - Wrong State: %d", __FUNCTION__, p_cb->state); + return; + } + + if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) { + SMP_TRACE_ERROR ("%s() - Wrong BD Addr", __FUNCTION__); + return; + } + + if (btm_find_dev (bd_addr) == NULL) { + SMP_TRACE_ERROR ("%s() - no dev CB", __FUNCTION__); + return; + } + + if (res != SMP_SUCCESS) { + SMP_TRACE_WARNING ("%s() - Numeric Comparison fails", __FUNCTION__); + /* send pairing failure */ + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + } else { + smp_sm_event(p_cb, SMP_SC_NC_OK_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function SMP_OobDataReply +** +** Description This function is called to provide the OOB data for +** SMP in response to SMP_OOB_REQ_EVT +** +** Parameters: bd_addr - Address of the peer device +** res - result of the operation SMP_SUCCESS if success +** p_data - simple pairing Randomizer C. +** +*******************************************************************************/ +void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, UINT8 len, UINT8 *p_data) +{ + tSMP_CB *p_cb = & smp_cb; + UINT8 failure = SMP_OOB_FAIL; + tSMP_KEY key; + + SMP_TRACE_EVENT ("%s State: %d res:%d", __FUNCTION__, smp_cb.state, res); + + /* If timeout already expired or has been canceled, ignore the reply */ + if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_OOB_REQ_EVT) { + return; + } + + if (res != SMP_SUCCESS || len == 0 || !p_data) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + } else { + if (len > BT_OCTET16_LEN) { + len = BT_OCTET16_LEN; + } + + memcpy(p_cb->tk, p_data, len); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = p_cb->tk; + + smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key); + } +} + +/******************************************************************************* +** +** Function SMP_SecureConnectionOobDataReply +** +** Description This function is called to provide the SC OOB data for +** SMP in response to SMP_SC_OOB_REQ_EVT +** +** Parameters: p_data - pointer to the data +** +*******************************************************************************/ +void SMP_SecureConnectionOobDataReply(UINT8 *p_data) +{ + tSMP_CB *p_cb = &smp_cb; + + UINT8 failure = SMP_OOB_FAIL; + tSMP_SC_OOB_DATA *p_oob = (tSMP_SC_OOB_DATA *) p_data; + if (!p_oob) { + SMP_TRACE_ERROR("%s received no data", __FUNCTION__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + return; + } + + /* Set local oob data when req_oob_type = SMP_OOB_BOTH */ + memcpy(&p_oob->loc_oob_data, smp_get_local_oob_data(), sizeof(tSMP_LOC_OOB_DATA)); + + SMP_TRACE_EVENT ("%s req_oob_type: %d, loc_oob_data.present: %d, " + "peer_oob_data.present: %d", + __FUNCTION__, p_cb->req_oob_type, p_oob->loc_oob_data.present, + p_oob->peer_oob_data.present); + + if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_SC_OOB_REQ_EVT) { + return; + } + + BOOLEAN data_missing = FALSE; + switch (p_cb->req_oob_type) { + case SMP_OOB_PEER: + if (!p_oob->peer_oob_data.present) { + data_missing = TRUE; + } + break; + case SMP_OOB_LOCAL: + if (!p_oob->loc_oob_data.present) { + data_missing = TRUE; + } + break; + case SMP_OOB_BOTH: + if (!p_oob->loc_oob_data.present || !p_oob->peer_oob_data.present) { + data_missing = TRUE; + } + break; + default: + SMP_TRACE_EVENT ("Unexpected OOB data type requested. Fail OOB"); + data_missing = TRUE; + break; + } + + if (data_missing) { + SMP_TRACE_ERROR("%s data missing", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + return; + } + + p_cb->sc_oob_data = *p_oob; + + smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, p_data); +} + +/******************************************************************************* +** +** Function SMP_Encrypt +** +** Description This function is called to encrypt the data with the specified +** key +** +** Parameters: key - Pointer to key key[0] conatins the MSB +** key_len - key length +** plain_text - Pointer to data to be encrypted +** plain_text[0] conatins the MSB +** pt_len - plain text length +** p_out - output of the encrypted texts +** +** Returns Boolean - request is successful +*******************************************************************************/ +BOOLEAN SMP_Encrypt (UINT8 *key, UINT8 key_len, + UINT8 *plain_text, UINT8 pt_len, + tSMP_ENC *p_out) + +{ + BOOLEAN status = FALSE; + status = smp_encrypt_data(key, key_len, plain_text, pt_len, p_out); + return status; +} + +/******************************************************************************* +** +** Function SMP_KeypressNotification +** +** Description This function is called to notify Security Manager about Keypress Notification. +** +** Parameters: bd_addr Address of the device to send keypress notification to +** value Keypress notification parameter value +** +*******************************************************************************/ +void SMP_KeypressNotification (BD_ADDR bd_addr, UINT8 value) +{ + tSMP_CB *p_cb = &smp_cb; + + SMP_TRACE_EVENT ("%s: Value: %d", __FUNCTION__, value); + + if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) { + SMP_TRACE_ERROR ("%s() - Wrong BD Addr", __FUNCTION__); + return; + } + + if (btm_find_dev (bd_addr) == NULL) { + SMP_TRACE_ERROR ("%s() - no dev CB", __FUNCTION__); + return; + } + + /* Keypress Notification is used by a device with KeyboardOnly IO capabilities */ + /* during the passkey entry protocol */ + if (p_cb->local_io_capability != SMP_IO_CAP_IN) { + SMP_TRACE_ERROR ("%s() - wrong local IO capabilities %d", + __FUNCTION__, p_cb->local_io_capability); + return; + } + + if (p_cb->selected_association_model != SMP_MODEL_SEC_CONN_PASSKEY_ENT) { + SMP_TRACE_ERROR ("%s() - wrong protocol %d", __FUNCTION__, + p_cb->selected_association_model); + return; + } + + smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &value); +} + +/******************************************************************************* +** +** Function SMP_CreateLocalSecureConnectionsOobData +** +** Description This function is called to start creation of local SC OOB +** data set (tSMP_LOC_OOB_DATA). +** +** Returns Boolean - TRUE: creation of local SC OOB data set started. +*******************************************************************************/ +BOOLEAN SMP_CreateLocalSecureConnectionsOobData (void) +{ + tSMP_CB *p_cb = &smp_cb; + + SMP_TRACE_EVENT ("%s state: %u, br_state: %u", __FUNCTION__, p_cb->state, p_cb->br_state); + + if ((p_cb->state != SMP_STATE_IDLE) || (p_cb->smp_over_br)) { + SMP_TRACE_WARNING ("%s creation of local OOB data set "\ + "starts only in IDLE state", __FUNCTION__); + return FALSE; + } + + smp_sm_event(p_cb, SMP_CR_LOC_SC_OOB_DATA_EVT, NULL); + + return TRUE; +} + +#endif /* SMP_INCLUDED */ diff --git a/lib/bt/host/bluedroid/stack/smp/smp_br_main.c b/lib/bt/host/bluedroid/stack/smp/smp_br_main.c new file mode 100644 index 00000000..5ef7a7c6 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/smp_br_main.c @@ -0,0 +1,369 @@ +/****************************************************************************** + * + * Copyright (C) 2014-2015 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "common/bt_target.h" + +#include <string.h> +#include "smp_int.h" + +#if ( CLASSIC_BT_INCLUDED== TRUE && SMP_INCLUDED == TRUE) + +const char *const smp_br_state_name [SMP_BR_STATE_MAX + 1] = { + "SMP_BR_STATE_IDLE", + "SMP_BR_STATE_WAIT_APP_RSP", + "SMP_BR_STATE_PAIR_REQ_RSP", + "SMP_BR_STATE_BOND_PENDING", + "SMP_BR_STATE_OUT_OF_RANGE" +}; + +const char *const smp_br_event_name [SMP_BR_MAX_EVT] = { + "BR_PAIRING_REQ_EVT", + "BR_PAIRING_RSP_EVT", + "BR_CONFIRM_EVT", + "BR_RAND_EVT", + "BR_PAIRING_FAILED_EVT", + "BR_ENCRPTION_INFO_EVT", + "BR_MASTER_ID_EVT", + "BR_ID_INFO_EVT", + "BR_ID_ADDR_EVT", + "BR_SIGN_INFO_EVT", + "BR_SECURITY_REQ_EVT", + "BR_PAIR_PUBLIC_KEY_EVT", + "BR_PAIR_DHKEY_CHCK_EVT", + "BR_PAIR_KEYPR_NOTIF_EVT", + "BR_KEY_READY_EVT", + "BR_ENCRYPTED_EVT", + "BR_L2CAP_CONN_EVT", + "BR_L2CAP_DISCONN_EVT", + "BR_KEYS_RSP_EVT", + "BR_API_SEC_GRANT_EVT", + "BR_TK_REQ_EVT", + "BR_AUTH_CMPL_EVT", + "BR_ENC_REQ_EVT", + "BR_BOND_REQ_EVT", + "BR_DISCARD_SEC_REQ_EVT", + "BR_OUT_OF_RANGE_EVT" +}; + +const char *smp_get_br_event_name(tSMP_BR_EVENT event); +const char *smp_get_br_state_name(tSMP_BR_STATE state); + +#define SMP_BR_SM_IGNORE 0 +#define SMP_BR_NUM_ACTIONS 2 +#define SMP_BR_SME_NEXT_STATE 2 +#define SMP_BR_SM_NUM_COLS 3 +typedef const UINT8 (*tSMP_BR_SM_TBL)[SMP_BR_SM_NUM_COLS]; + +enum { + SMP_SEND_PAIR_REQ, + SMP_BR_SEND_PAIR_RSP, + SMP_SEND_PAIR_FAIL, + SMP_SEND_ID_INFO, + SMP_BR_PROC_PAIR_CMD, + SMP_PROC_PAIR_FAIL, + SMP_PROC_ID_INFO, + SMP_PROC_ID_ADDR, + SMP_PROC_SRK_INFO, + SMP_BR_PROC_SEC_GRANT, + SMP_BR_PROC_SL_KEYS_RSP, + SMP_BR_KEY_DISTRIBUTION, + SMP_BR_PAIRING_COMPLETE, + SMP_SEND_APP_CBACK, + SMP_BR_CHECK_AUTH_REQ, + SMP_PAIR_TERMINATE, + SMP_IDLE_TERMINATE, + SMP_BR_SM_NO_ACTION +}; + +static const tSMP_ACT smp_br_sm_action[] = { + smp_send_pair_req, + smp_br_send_pair_response, + smp_send_pair_fail, + smp_send_id_info, + smp_br_process_pairing_command, + smp_proc_pair_fail, + smp_proc_id_info, + smp_proc_id_addr, + smp_proc_srk_info, + smp_br_process_security_grant, + smp_br_process_slave_keys_response, + smp_br_select_next_key, + smp_br_pairing_complete, + smp_send_app_cback, + smp_br_check_authorization_request, + smp_pair_terminate, + smp_idle_terminate +}; + +static const UINT8 smp_br_all_table[][SMP_BR_SM_NUM_COLS] = { + /* Event Action Next State */ + /* BR_PAIRING_FAILED */ {SMP_PROC_PAIR_FAIL, SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE}, + /* BR_AUTH_CMPL */ {SMP_SEND_PAIR_FAIL, SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE}, + /* BR_L2CAP_DISCONN */ {SMP_PAIR_TERMINATE, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE} +}; + +/************ SMP Master FSM State/Event Indirection Table **************/ +static const UINT8 smp_br_master_entry_map[][SMP_BR_STATE_MAX] = { + /* br_state name: Idle WaitApp Pair Bond + Rsp ReqRsp Pend */ + /* BR_PAIRING_REQ */ { 0, 0, 0, 0 }, + /* BR_PAIRING_RSP */ { 0, 0, 1, 0 }, + /* BR_CONFIRM */ { 0, 0, 0, 0 }, + /* BR_RAND */ { 0, 0, 0, 0 }, + /* BR_PAIRING_FAILED */ { 0, 0x81, 0x81, 0 }, + /* BR_ENCRPTION_INFO */ { 0, 0, 0, 0 }, + /* BR_MASTER_ID */ { 0, 0, 0, 0 }, + /* BR_ID_INFO */ { 0, 0, 0, 1 }, + /* BR_ID_ADDR */ { 0, 0, 0, 2 }, + /* BR_SIGN_INFO */ { 0, 0, 0, 3 }, + /* BR_SECURITY_REQ */ { 0, 0, 0, 0 }, + /* BR_PAIR_PUBLIC_KEY_EVT */ { 0, 0, 0, 0 }, + /* BR_PAIR_DHKEY_CHCK_EVT */ { 0, 0, 0, 0 }, + /* BR_PAIR_KEYPR_NOTIF_EVT */ { 0, 0, 0, 0 }, + /* BR_KEY_READY */ { 0, 0, 0, 0 }, + /* BR_ENCRYPTED */ { 0, 0, 0, 0 }, + /* BR_L2CAP_CONN */ { 1, 0, 0, 0 }, + /* BR_L2CAP_DISCONN */ { 2, 0x83, 0x83, 0x83 }, + /* BR_KEYS_RSP */ { 0, 1, 0, 0 }, + /* BR_API_SEC_GRANT */ { 0, 0, 0, 0 }, + /* BR_TK_REQ */ { 0, 0, 0, 0 }, + /* BR_AUTH_CMPL */ { 0, 0x82, 0x82, 0x82 }, + /* BR_ENC_REQ */ { 0, 0, 0, 0 }, + /* BR_BOND_REQ */ { 0, 0, 2, 0 }, + /* BR_DISCARD_SEC_REQ */ { 0, 0, 0, 0 } +}; + +static const UINT8 smp_br_master_idle_table[][SMP_BR_SM_NUM_COLS] = { + /* Event Action Next State */ + /* BR_L2CAP_CONN */ {SMP_SEND_APP_CBACK, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_WAIT_APP_RSP}, + /* BR_L2CAP_DISCONN */ {SMP_IDLE_TERMINATE, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE} +}; + +static const UINT8 smp_br_master_wait_appln_response_table[][SMP_BR_SM_NUM_COLS] = { + /* Event Action Next State */ + /* BR_KEYS_RSP */{SMP_SEND_PAIR_REQ, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_PAIR_REQ_RSP} +}; + +static const UINT8 smp_br_master_pair_request_response_table [][SMP_BR_SM_NUM_COLS] = { + /* Event Action Next State */ + /* BR_PAIRING_RSP */ {SMP_BR_PROC_PAIR_CMD, SMP_BR_CHECK_AUTH_REQ, SMP_BR_STATE_PAIR_REQ_RSP}, + /* BR_BOND_REQ */ {SMP_BR_SM_NO_ACTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING} +}; + +static const UINT8 smp_br_master_bond_pending_table[][SMP_BR_SM_NUM_COLS] = { + /* Event Action Next State */ + /* BR_ID_INFO */{SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}, + /* BR_ID_ADDR */{SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}, + /* BR_SIGN_INFO */{SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING} +}; + +static const UINT8 smp_br_slave_entry_map[][SMP_BR_STATE_MAX] = { + /* br_state name: Idle WaitApp Pair Bond + Rsp ReqRsp Pend */ + /* BR_PAIRING_REQ */ { 1, 0, 0, 0 }, + /* BR_PAIRING_RSP */ { 0, 0, 0, 0 }, + /* BR_CONFIRM */ { 0, 0, 0, 0 }, + /* BR_RAND */ { 0, 0, 0, 0 }, + /* BR_PAIRING_FAILED */ { 0, 0x81, 0x81, 0x81 }, + /* BR_ENCRPTION_INFO */ { 0, 0, 0, 0 }, + /* BR_MASTER_ID */ { 0, 0, 0, 0 }, + /* BR_ID_INFO */ { 0, 0, 0, 1 }, + /* BR_ID_ADDR */ { 0, 0, 0, 2 }, + /* BR_SIGN_INFO */ { 0, 0, 0, 3 }, + /* BR_SECURITY_REQ */ { 0, 0, 0, 0 }, + /* BR_PAIR_PUBLIC_KEY_EVT */ { 0, 0, 0, 0 }, + /* BR_PAIR_DHKEY_CHCK_EVT */ { 0, 0, 0, 0 }, + /* BR_PAIR_KEYPR_NOTIF_EVT */ { 0, 0, 0, 0 }, + /* BR_KEY_READY */ { 0, 0, 0, 0 }, + /* BR_ENCRYPTED */ { 0, 0, 0, 0 }, + /* BR_L2CAP_CONN */ { 0, 0, 0, 0 }, + /* BR_L2CAP_DISCONN */ { 0, 0x83, 0x83, 0x83 }, + /* BR_KEYS_RSP */ { 0, 2, 0, 0 }, + /* BR_API_SEC_GRANT */ { 0, 1, 0, 0 }, + /* BR_TK_REQ */ { 0, 0, 0, 0 }, + /* BR_AUTH_CMPL */ { 0, 0x82, 0x82, 0x82 }, + /* BR_ENC_REQ */ { 0, 0, 0, 0 }, + /* BR_BOND_REQ */ { 0, 3, 0, 0 }, + /* BR_DISCARD_SEC_REQ */ { 0, 0, 0, 0 } +}; + +static const UINT8 smp_br_slave_idle_table[][SMP_BR_SM_NUM_COLS] = { + /* Event Action Next State */ + /* BR_PAIRING_REQ */ {SMP_BR_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP} +}; + +static const UINT8 smp_br_slave_wait_appln_response_table [][SMP_BR_SM_NUM_COLS] = { + /* Event Action Next State */ + /* BR_API_SEC_GRANT */ {SMP_BR_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP}, + /* BR_KEYS_RSP */{SMP_BR_PROC_SL_KEYS_RSP, SMP_BR_CHECK_AUTH_REQ, SMP_BR_STATE_WAIT_APP_RSP}, + /* BR_BOND_REQ */ {SMP_BR_KEY_DISTRIBUTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING} +}; + +static const UINT8 smp_br_slave_bond_pending_table[][SMP_BR_SM_NUM_COLS] = { + /* Event Action Next State */ + /* BR_ID_INFO */ {SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}, + /* BR_ID_ADDR */ {SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}, + /* BR_SIGN_INFO */ {SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING} +}; + +static const tSMP_BR_SM_TBL smp_br_state_table[][2] = { + /* SMP_BR_STATE_IDLE */ + {smp_br_master_idle_table, smp_br_slave_idle_table}, + + /* SMP_BR_STATE_WAIT_APP_RSP */ + {smp_br_master_wait_appln_response_table, smp_br_slave_wait_appln_response_table}, + + /* SMP_BR_STATE_PAIR_REQ_RSP */ + {smp_br_master_pair_request_response_table, NULL}, + + /* SMP_BR_STATE_BOND_PENDING */ + {smp_br_master_bond_pending_table, smp_br_slave_bond_pending_table}, +}; + +typedef const UINT8 (*tSMP_BR_ENTRY_TBL)[SMP_BR_STATE_MAX]; + +static const tSMP_BR_ENTRY_TBL smp_br_entry_table[] = { + smp_br_master_entry_map, + smp_br_slave_entry_map +}; + +#define SMP_BR_ALL_TABLE_MASK 0x80 + +/******************************************************************************* +** Function smp_set_br_state +** Returns None +*******************************************************************************/ +void smp_set_br_state(tSMP_BR_STATE br_state) +{ + if (br_state < SMP_BR_STATE_MAX) { + SMP_TRACE_DEBUG( "BR_State change: %s(%d) ==> %s(%d)", + smp_get_br_state_name(smp_cb.br_state), smp_cb.br_state, + smp_get_br_state_name(br_state), br_state ); + smp_cb.br_state = br_state; + } else { + SMP_TRACE_DEBUG("%s invalid br_state =%d", __FUNCTION__, br_state ); + } +} + +/******************************************************************************* +** Function smp_get_br_state +** Returns The smp_br state +*******************************************************************************/ +tSMP_BR_STATE smp_get_br_state(void) +{ + return smp_cb.br_state; +} + +/******************************************************************************* +** Function smp_get_br_state_name +** Returns The smp_br state name. +*******************************************************************************/ +const char *smp_get_br_state_name(tSMP_BR_STATE br_state) +{ + const char *p_str = smp_br_state_name[SMP_BR_STATE_MAX]; + + if (br_state < SMP_BR_STATE_MAX) { + p_str = smp_br_state_name[br_state]; + } + + return p_str; +} +/******************************************************************************* +** Function smp_get_br_event_name +** Returns The smp_br event name. +*******************************************************************************/ +const char *smp_get_br_event_name(tSMP_BR_EVENT event) +{ + const char *p_str = smp_br_event_name[SMP_BR_MAX_EVT - 1]; + + if (event < SMP_BR_MAX_EVT) { + p_str = smp_br_event_name[event - 1]; + } + return p_str; +} + +/******************************************************************************* +** +** Function smp_br_state_machine_event +** +** Description Handle events to the state machine. It looks up the entry +** in the smp_br_entry_table array. +** If it is a valid entry, it gets the state table.Set the next state, +** if not NULL state. Execute the action function according to the +** state table. If the state returned by action function is not NULL +** state, adjust the new state to the returned state. +** +** Returns void. +** +*******************************************************************************/ +void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data) +{ + tSMP_BR_STATE curr_state = p_cb->br_state; + tSMP_BR_SM_TBL state_table; + UINT8 action, entry; + tSMP_BR_ENTRY_TBL entry_table = smp_br_entry_table[p_cb->role]; + + SMP_TRACE_EVENT("main %s", __func__); + if (curr_state >= SMP_BR_STATE_MAX) { + SMP_TRACE_DEBUG( "Invalid br_state: %d", curr_state) ; + return; + } + + SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]", + (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master", + smp_get_br_state_name( p_cb->br_state), + p_cb->br_state, smp_get_br_event_name(event), event) ; + + /* look up the state table for the current state */ + /* lookup entry / w event & curr_state */ + /* If entry is ignore, return. + * Otherwise, get state table (according to curr_state or all_state) */ + if ((event <= SMP_BR_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state]) + != SMP_BR_SM_IGNORE )) { + if (entry & SMP_BR_ALL_TABLE_MASK) { + entry &= ~SMP_BR_ALL_TABLE_MASK; + state_table = smp_br_all_table; + } else { + state_table = smp_br_state_table[curr_state][p_cb->role]; + } + } else { + SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]", + smp_get_br_event_name(event), event, + smp_get_br_state_name(curr_state), curr_state); + return; + } + + /* Get possible next state from state table. */ + + smp_set_br_state(state_table[entry - 1][SMP_BR_SME_NEXT_STATE]); + + /* If action is not ignore, clear param, exec action and get next state. + * The action function may set the Param for cback. + * Depending on param, call cback or free buffer. */ + /* execute action functions */ + for (UINT8 i = 0; i < SMP_BR_NUM_ACTIONS; i++) { + if ((action = state_table[entry - 1][i]) != SMP_BR_SM_NO_ACTION) { + (*smp_br_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data); + } else { + break; + } + } + SMP_TRACE_DEBUG( "result state = %s", smp_get_br_state_name( p_cb->br_state ) ) ; +} + +#endif diff --git a/lib/bt/host/bluedroid/stack/smp/smp_cmac.c b/lib/bt/host/bluedroid/stack/smp/smp_cmac.c new file mode 100644 index 00000000..e47c56b7 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/smp_cmac.c @@ -0,0 +1,369 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the implementation of the AES128 CMAC algorithm. + * + ******************************************************************************/ + +#include "common/bt_target.h" +#include "osi/allocator.h" + +#if SMP_INCLUDED == TRUE +// #include <stdio.h> +#include <string.h> + +#include "stack/btm_ble_api.h" +#include "smp_int.h" +#include "stack/hcimsgs.h" + +typedef struct { + UINT8 *text; + UINT16 len; + UINT16 round; +} tCMAC_CB; + +tCMAC_CB cmac_cb; + +/* Rb for AES-128 as block cipher, LSB as [0] */ +const BT_OCTET16 const_Rb = { + 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void print128(BT_OCTET16 x, const UINT8 *key_name) +{ +#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE + UINT8 *p = (UINT8 *)x; + UINT8 i; + + SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name); + + for (i = 0; i < 4; i ++) { + SMP_TRACE_WARNING("%02x %02x %02x %02x", + p[BT_OCTET16_LEN - i * 4 - 1], p[BT_OCTET16_LEN - i * 4 - 2], + p[BT_OCTET16_LEN - i * 4 - 3], p[BT_OCTET16_LEN - i * 4 - 4]); + } +#endif +} + +/******************************************************************************* +** +** Function padding +** +** Description utility function to padding the given text to be a 128 bits +** data. The parameter dest is input and output parameter, it +** must point to a BT_OCTET16_LEN memory space; where include +** length bytes valid data. +** +** Returns void +** +*******************************************************************************/ +static void padding ( BT_OCTET16 dest, UINT8 length ) +{ + UINT8 i, *p = dest; + /* original last block */ + for ( i = length ; i < BT_OCTET16_LEN; i++ ) { + p[BT_OCTET16_LEN - i - 1] = ( i == length ) ? 0x80 : 0; + } +} +/******************************************************************************* +** +** Function leftshift_onebit +** +** Description utility function to left shift one bit for a 128 bits value. +** +** Returns void +** +*******************************************************************************/ +static void leftshift_onebit(UINT8 *input, UINT8 *output) +{ + UINT8 i, overflow = 0 , next_overflow = 0; + SMP_TRACE_EVENT ("leftshift_onebit "); + /* input[0] is LSB */ + for ( i = 0; i < BT_OCTET16_LEN ; i ++ ) { + next_overflow = (input[i] & 0x80) ? 1 : 0; + output[i] = (input[i] << 1) | overflow; + overflow = next_overflow; + } + return; +} +/******************************************************************************* +** +** Function cmac_aes_cleanup +** +** Description clean up function for AES_CMAC algorithm. +** +** Returns void +** +*******************************************************************************/ +static void cmac_aes_cleanup(void) +{ + if (cmac_cb.text != NULL) { + osi_free(cmac_cb.text); + } + memset(&cmac_cb, 0, sizeof(tCMAC_CB)); +} + +/******************************************************************************* +** +** Function cmac_aes_k_calculate +** +** Description This function is the calculation of block cipher using AES-128. +** +** Returns void +** +*******************************************************************************/ +static BOOLEAN cmac_aes_k_calculate(BT_OCTET16 key, UINT8 *p_signature, UINT16 tlen) +{ + tSMP_ENC output; + UINT16 i = 1, err = 0; + UINT8 x[16] = {0}; + UINT8 *p_mac; + + SMP_TRACE_EVENT ("cmac_aes_k_calculate "); + + while (i <= cmac_cb.round) { + smp_xor_128(&cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], x); /* Mi' := Mi (+) X */ + + if (!SMP_Encrypt(key, BT_OCTET16_LEN, &cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], BT_OCTET16_LEN, &output)) { + err = 1; + break; + } + + memcpy(x, output.param_buf, BT_OCTET16_LEN); + i ++; + } + + if (!err) { + p_mac = output.param_buf + (BT_OCTET16_LEN - tlen); + memcpy(p_signature, p_mac, tlen); + + SMP_TRACE_DEBUG("tlen = %d p_mac = %p", tlen, p_mac); + SMP_TRACE_DEBUG("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x", + *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3)); + SMP_TRACE_DEBUG("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x", + *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7)); + + return TRUE; + + } else { + return FALSE; + } +} +/******************************************************************************* +** +** Function cmac_prepare_last_block +** +** Description This function proceeed to prepare the last block of message +** Mn depending on the size of the message. +** +** Returns void +** +*******************************************************************************/ +static void cmac_prepare_last_block (BT_OCTET16 k1, BT_OCTET16 k2) +{ +// UINT8 x[16] = {0}; + BOOLEAN flag; + + SMP_TRACE_EVENT ("cmac_prepare_last_block "); + /* last block is a complete block set flag to 1 */ + flag = ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? TRUE : FALSE; + + SMP_TRACE_DEBUG("flag = %d round = %d", flag, cmac_cb.round); + + if ( flag ) { + /* last block is complete block */ + smp_xor_128(&cmac_cb.text[0], k1); + } else { /* padding then xor with k2 */ + padding(&cmac_cb.text[0], (UINT8)(cmac_cb.len % 16)); + + smp_xor_128(&cmac_cb.text[0], k2); + } +} +/******************************************************************************* +** +** Function cmac_subkey_cont +** +** Description This is the callback function when CIPHk(0[128]) is completed. +** +** Returns void +** +*******************************************************************************/ +static void cmac_subkey_cont(tSMP_ENC *p) +{ + UINT8 k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN]; + UINT8 *pp = p->param_buf; + SMP_TRACE_EVENT ("cmac_subkey_cont "); + print128(pp, (const UINT8 *)"K1 before shift"); + + /* If MSB(L) = 0, then K1 = L << 1 */ + if ( (pp[BT_OCTET16_LEN - 1] & 0x80) != 0 ) { + /* Else K1 = ( L << 1 ) (+) Rb */ + leftshift_onebit(pp, k1); + smp_xor_128(k1, const_Rb); + } else { + leftshift_onebit(pp, k1); + } + + if ( (k1[BT_OCTET16_LEN - 1] & 0x80) != 0 ) { + /* K2 = (K1 << 1) (+) Rb */ + leftshift_onebit(k1, k2); + smp_xor_128(k2, const_Rb); + } else { + /* If MSB(K1) = 0, then K2 = K1 << 1 */ + leftshift_onebit(k1, k2); + } + + print128(k1, (const UINT8 *)"K1"); + print128(k2, (const UINT8 *)"K2"); + + cmac_prepare_last_block (k1, k2); +} +/******************************************************************************* +** +** Function cmac_generate_subkey +** +** Description This is the function to generate the two subkeys. +** +** Parameters key - CMAC key, expect SRK when used by SMP. +** +** Returns void +** +*******************************************************************************/ +static BOOLEAN cmac_generate_subkey(BT_OCTET16 key) +{ + BT_OCTET16 z = {0}; + BOOLEAN ret = TRUE; + tSMP_ENC output; + SMP_TRACE_EVENT (" cmac_generate_subkey"); + + if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) { + cmac_subkey_cont(&output);; + } else { + ret = FALSE; + } + + return ret; +} +/******************************************************************************* +** +** Function aes_cipher_msg_auth_code +** +** Description This is the AES-CMAC Generation Function with tlen implemented. +** +** Parameters key - CMAC key in little endian order, expect SRK when used by SMP. +** input - text to be signed in little endian byte order. +** length - length of the input in byte. +** tlen - lenth of mac desired +** p_signature - data pointer to where signed data to be stored, tlen long. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +*******************************************************************************/ +BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length, + UINT16 tlen, UINT8 *p_signature) +{ + UINT16 len, diff; + UINT16 n = (length + BT_OCTET16_LEN - 1) / BT_OCTET16_LEN; /* n is number of rounds */ + BOOLEAN ret = FALSE; + + SMP_TRACE_EVENT ("%s", __func__); + + if (n == 0) { + n = 1; + } + len = n * BT_OCTET16_LEN; + + SMP_TRACE_DEBUG("AES128_CMAC started, allocate buffer size = %d", len); + /* allocate a memory space of multiple of 16 bytes to hold text */ + if ((cmac_cb.text = (UINT8 *)osi_malloc(len)) != NULL) { + cmac_cb.round = n; + + memset(cmac_cb.text, 0, len); + diff = len - length; + + if (input != NULL && length > 0) { + memcpy(&cmac_cb.text[diff] , input, (int)length); + cmac_cb.len = length; + } else { + cmac_cb.len = 0; + } + + /* prepare calculation for subkey s and last block of data */ + if (cmac_generate_subkey(key)) { + /* start calculation */ + ret = cmac_aes_k_calculate(key, p_signature, tlen); + } + /* clean up */ + cmac_aes_cleanup(); + } else { + ret = FALSE; + SMP_TRACE_ERROR("No resources"); + } + + return ret; +} + +#if 0 /* testing code, sample data from spec */ +void test_cmac_cback(UINT8 *p_mac, UINT16 tlen) +{ + SMP_TRACE_EVENT ("test_cmac_cback "); + SMP_TRACE_ERROR("test_cmac_cback"); +} + +void test_cmac(void) +{ + SMP_TRACE_EVENT ("test_cmac "); + UINT8 M[64] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }; + + UINT8 key[16] = { + 0x3c, 0x4f, 0xcf, 0x09, 0x88, 0x15, 0xf7, 0xab, + 0xa6, 0xd2, 0xae, 0x28, 0x16, 0x15, 0x7e, 0x2b + }; + UINT8 i = 0, tmp; + UINT16 len; + + len = 64; + + for (i = 0; i < len / 2; i ++) { + tmp = M[i]; + M[i] = M[len - 1 - i]; + M[len - 1 - i] = tmp; + } + + + memset(&cmac_cb, 0, sizeof(tCMAC_CB)); + + SMP_TRACE_WARNING("\n Example 1: len = %d\n", len); + + aes_cipher_msg_auth_code(key, M, len, 128, test_cmac_cback, 0); + +} +#endif +#endif diff --git a/lib/bt/host/bluedroid/stack/smp/smp_keys.c b/lib/bt/host/bluedroid/stack/smp/smp_keys.c new file mode 100644 index 00000000..aec6f709 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/smp_keys.c @@ -0,0 +1,2293 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains security manager protocol utility functions + * + ******************************************************************************/ +#include "common/bt_target.h" + +#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) +#if SMP_DEBUG == TRUE +#include <stdio.h> +#endif +#include <string.h> +//#include "bt_utils.h" +#include "stack/btm_ble_api.h" +#include "smp_int.h" +#include "btm_int.h" +#include "btm_ble_int.h" +#include "stack/hcimsgs.h" +#include "aes.h" +#include "p_256_ecc_pp.h" +#include "device/controller.h" + +#ifndef SMP_MAX_ENC_REPEAT +#define SMP_MAX_ENC_REPEAT 3 +#endif + +static void smp_rand_back(tBTM_RAND_ENC *p); +static void smp_generate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +static void smp_generate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data); +static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p); +static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p); +static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p); +static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p); +static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p); +static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p); +static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p); +static BOOLEAN smp_calculate_legacy_short_term_key(tSMP_CB *p_cb, tSMP_ENC *output); +static void smp_continue_private_key_creation(tSMP_CB *p_cb, tBTM_RAND_ENC *p); +static void smp_process_private_key(tSMP_CB *p_cb); +static void smp_finish_nonce_generation(tSMP_CB *p_cb); +static void smp_process_new_nonce(tSMP_CB *p_cb); + +static const tSMP_ACT smp_encrypt_action[] = { + smp_generate_compare, /* SMP_GEN_COMPARE */ + smp_generate_confirm, /* SMP_GEN_CONFIRM*/ + smp_generate_stk, /* SMP_GEN_STK*/ + smp_generate_ltk_cont, /* SMP_GEN_LTK */ + smp_generate_ltk, /* SMP_GEN_DIV_LTK */ + smp_generate_rand_vector, /* SMP_GEN_RAND_V */ + smp_generate_y, /* SMP_GEN_EDIV */ + smp_generate_passkey, /* SMP_GEN_TK */ + smp_generate_srand_mrand_confirm, /* SMP_GEN_SRAND_MRAND */ + smp_generate_rand_cont /* SMP_GEN_SRAND_MRAND_CONT */ +}; + +/* If there is data saved here, then use its info instead + * This needs to be cleared on a successful pairing using the oob data + */ +static tSMP_LOC_OOB_DATA saved_local_oob_data = {}; + +void smp_save_local_oob_data(tSMP_CB *p_cb) +{ + memcpy(&saved_local_oob_data, &p_cb->sc_oob_data.loc_oob_data, sizeof(tSMP_LOC_OOB_DATA)); +} + +void smp_clear_local_oob_data(void) +{ + memset(&saved_local_oob_data, 0, sizeof(tSMP_LOC_OOB_DATA)); +} + +static BOOLEAN oob_data_is_empty(tSMP_LOC_OOB_DATA *data) +{ + tSMP_LOC_OOB_DATA empty_data = {0}; + return (memcmp(data, &empty_data, sizeof(tSMP_LOC_OOB_DATA)) == 0); +} + +tSMP_LOC_OOB_DATA *smp_get_local_oob_data(void) +{ + return &saved_local_oob_data; +} + +void smp_debug_print_nbyte_little_endian(UINT8 *p, const UINT8 *key_name, UINT8 len) +{ +#if SMP_DEBUG == TRUE + int ind, x; + int col_count = 32; + int row_count; + UINT8 p_buf[512]; + + SMP_TRACE_WARNING("%s(LSB ~ MSB):\n", key_name); + memset(p_buf, 0, sizeof(p_buf)); + row_count = len % col_count ? len / col_count + 1 : len / col_count; + + ind = 0; + for (int row = 0; row < row_count; row++) { + for (int column = 0, x = 0; (ind < len) && (column < col_count); column++, ind++) { + x += sprintf((char *)&p_buf[x], "%02x ", p[ind]); + } + SMP_TRACE_WARNING(" [%03d]: %s", row * col_count, p_buf); + } +#endif +} + +#if 0 //Unused +void smp_debug_print_nbyte_big_endian (UINT8 *p, const UINT8 *key_name, UINT8 len) +{ +#if SMP_DEBUG == TRUE + UINT8 p_buf[512]; + + SMP_TRACE_WARNING("%s(MSB ~ LSB):", key_name); + memset(p_buf, 0, sizeof(p_buf)); + nrows = len % ncols ? len / ncols + 1 : len / ncols; + + int ind = 0; + int ncols = 32; /* num entries in one line */ + int nrows; /* num lines */ + int x; + + for (int row = 0; row < nrows; row++) { + for (int col = 0, x = 0; (ind < len) && (col < ncols); col++, ind++) { + x += sprintf ((char *)&p_buf[len - x - 1], "%02x ", p[ind]); + } + SMP_TRACE_WARNING("[%03d]: %s", row * ncols, p_buf); + } +#endif +} +#endif + +/******************************************************************************* +** +** Function smp_encrypt_data +** +** Description This function is called to encrypt data. +** It uses AES-128 encryption algorithm. +** Plain_text is encrypted using key, the result is at p_out. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len, + UINT8 *plain_text, UINT8 pt_len, + tSMP_ENC *p_out) +{ + aes_context ctx; + UINT8 *p_start = NULL; + UINT8 *p = NULL; + UINT8 *p_rev_data = NULL; /* input data in big endilan format */ + UINT8 *p_rev_key = NULL; /* input key in big endilan format */ + UINT8 *p_rev_output = NULL; /* encrypted output in big endilan format */ + + SMP_TRACE_DEBUG ("%s\n", __func__); + if ( (p_out == NULL ) || (key_len != SMP_ENCRYT_KEY_SIZE) ) { + SMP_TRACE_ERROR ("%s failed\n", __func__); + return FALSE; + } + + if ((p_start = (UINT8 *)osi_malloc((SMP_ENCRYT_DATA_SIZE * 4))) == NULL) { + SMP_TRACE_ERROR ("%s failed unable to allocate buffer\n", __func__); + return FALSE; + } + + if (pt_len > SMP_ENCRYT_DATA_SIZE) { + pt_len = SMP_ENCRYT_DATA_SIZE; + } + + memset(p_start, 0, SMP_ENCRYT_DATA_SIZE * 4); + p = p_start; + ARRAY_TO_STREAM (p, plain_text, pt_len); /* byte 0 to byte 15 */ + p_rev_data = p = p_start + SMP_ENCRYT_DATA_SIZE; /* start at byte 16 */ + REVERSE_ARRAY_TO_STREAM (p, p_start, SMP_ENCRYT_DATA_SIZE); /* byte 16 to byte 31 */ + p_rev_key = p; /* start at byte 32 */ + REVERSE_ARRAY_TO_STREAM (p, key, SMP_ENCRYT_KEY_SIZE); /* byte 32 to byte 47 */ + +#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE + smp_debug_print_nbyte_little_endian(key, (const UINT8 *)"Key", SMP_ENCRYT_KEY_SIZE); + smp_debug_print_nbyte_little_endian(p_start, (const UINT8 *)"Plain text", SMP_ENCRYT_DATA_SIZE); +#endif + p_rev_output = p; + aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx); + bluedroid_aes_encrypt(p_rev_data, p, &ctx); /* outputs in byte 48 to byte 63 */ + + p = p_out->param_buf; + REVERSE_ARRAY_TO_STREAM (p, p_rev_output, SMP_ENCRYT_DATA_SIZE); +#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE + smp_debug_print_nbyte_little_endian(p_out->param_buf, (const UINT8 *)"Encrypted text", SMP_ENCRYT_KEY_SIZE); +#endif + + p_out->param_len = SMP_ENCRYT_KEY_SIZE; + p_out->status = HCI_SUCCESS; + p_out->opcode = HCI_BLE_ENCRYPT; + + osi_free(p_start); + + return TRUE; +} + +void smp_use_static_passkey(void) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 *tt = p_cb->tk; + tSMP_KEY key; + UINT32 passkey = p_cb->static_passkey; + /* save the TK */ + memset(p_cb->tk, 0, BT_OCTET16_LEN); + UINT32_TO_STREAM(tt, passkey); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = p_cb->tk; + + if (p_cb->p_callback) { + (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda, (tSMP_EVT_DATA *)&passkey); + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_DISP) { + smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &passkey); + } else { + smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA *)&key); + } +} +/******************************************************************************* +** +** Function smp_generate_passkey +** +** Description This function is called to generate passkey. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_passkey(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + if(p_cb->use_static_passkey) { + SMP_TRACE_DEBUG ("%s use static passkey %6d", __func__, p_cb->static_passkey); + smp_use_static_passkey(); + return; + } + SMP_TRACE_DEBUG ("%s generate rand passkey", __func__); + p_cb->rand_enc_proc_state = SMP_GEN_TK; + + /* generate MRand or SRand */ + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** +** Function smp_proc_passkey +** +** Description This function is called to process a passkey. +** +** Returns void +** +*******************************************************************************/ +void smp_proc_passkey(tSMP_CB *p_cb , tBTM_RAND_ENC *p) +{ + UINT8 *tt = p_cb->tk; + tSMP_KEY key; + UINT32 passkey; /* 19655 test number; */ + UINT8 *pp = p->param_buf; + + SMP_TRACE_DEBUG ("%s", __func__); + STREAM_TO_UINT32(passkey, pp); + passkey &= ~SMP_PASSKEY_MASK; + + /* truncate by maximum value */ + while (passkey > BTM_MAX_PASSKEY_VAL) { + passkey >>= 1; + } + + /* save the TK */ + memset(p_cb->tk, 0, BT_OCTET16_LEN); + UINT32_TO_STREAM(tt, passkey); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = p_cb->tk; + + if (p_cb->p_callback) { + (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda, (tSMP_EVT_DATA *)&passkey); + } + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_DISP) { + smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &passkey); + } else { + smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA *)&key); + } +} + +/******************************************************************************* +** +** Function smp_generate_stk +** +** Description This function is called to generate STK calculated by running +** AES with the TK value as key and a concatenation of the random +** values. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_stk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("%s\n", __func__); + + if (p_cb->le_secure_connections_mode_is_used) { + SMP_TRACE_WARNING ("FOR LE SC LTK IS USED INSTEAD OF STK"); + output.param_len = SMP_ENCRYT_KEY_SIZE; + output.status = HCI_SUCCESS; + output.opcode = HCI_BLE_ENCRYPT; + memcpy(output.param_buf, p_cb->ltk, SMP_ENCRYT_DATA_SIZE); + } else if (!smp_calculate_legacy_short_term_key(p_cb, &output)) { + SMP_TRACE_ERROR("%s failed", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + return; + } + + smp_process_stk(p_cb, &output); +} + +/******************************************************************************* +** +** Function smp_generate_srand_mrand_confirm +** +** Description This function is called to start the second pairing phase by +** start generating random number. +** +** +** Returns void +** +*******************************************************************************/ +void smp_generate_srand_mrand_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("%s\n", __func__); + p_cb->rand_enc_proc_state = SMP_GEN_SRAND_MRAND; + /* generate MRand or SRand */ + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** +** Function smp_generate_rand_cont +** +** Description This function is called to generate another 64 bits random for +** MRand or Srand. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("%s\n", __func__); + p_cb->rand_enc_proc_state = SMP_GEN_SRAND_MRAND_CONT; + /* generate 64 MSB of MRand or SRand */ + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** +** Function smp_generate_ltk +** +** Description This function is called: +** - in legacy pairing - to calculate LTK, starting with DIV +** generation; +** - in LE Secure Connections pairing over LE transport - to process LTK +** already generated to encrypt LE link; +** - in LE Secure Connections pairing over BR/EDR transport - to start +** BR/EDR Link Key processing. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + BOOLEAN div_status; + SMP_TRACE_DEBUG ("%s\n", __FUNCTION__); +#if (CLASSIC_BT_INCLUDED == TRUE) + if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) { + smp_br_process_link_key(p_cb, NULL); + return; + } +#endif ///CLASSIC_BT_INCLUDED == TRUE + if (p_cb->le_secure_connections_mode_is_used) { + smp_process_secure_connection_long_term_key(); + return; + } + + div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div); + + if (div_status) { + smp_generate_ltk_cont(p_cb, NULL); + } else { + SMP_TRACE_DEBUG ("Generate DIV for LTK\n"); + p_cb->rand_enc_proc_state = SMP_GEN_DIV_LTK; + /* generate MRand or SRand */ + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } + } +} + +/******************************************************************************* +** +** Function smp_compute_csrk +** +** Description This function is called to calculate CSRK +** +** +** Returns void +** +*******************************************************************************/ +void smp_compute_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + BT_OCTET16 er; + UINT8 buffer[4]; /* for (r || DIV) r=1*/ + UINT16 r = 1; + UINT8 *p = buffer; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("smp_compute_csrk div=%x\n", p_cb->div); + BTM_GetDeviceEncRoot(er); + /* CSRK = d1(ER, DIV, 1) */ + UINT16_TO_STREAM(p, p_cb->div); + UINT16_TO_STREAM(p, r); + + if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output)) { + SMP_TRACE_ERROR("smp_generate_csrk failed\n"); + if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status); +#endif ///CLASSIC_BT_INCLUDED == TRUE + } else { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } + } else { + memcpy((void *)p_cb->csrk, output.param_buf, BT_OCTET16_LEN); + smp_send_csrk_info(p_cb, NULL); + } +} + +/******************************************************************************* +** +** Function smp_generate_csrk +** +** Description This function is called to calculate CSRK, starting with DIV +** generation. +** +** +** Returns void +** +*******************************************************************************/ +void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + BOOLEAN div_status; + + SMP_TRACE_DEBUG ("smp_generate_csrk"); + + div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div); + if (div_status) { + smp_compute_csrk(p_cb, NULL); + } else { + SMP_TRACE_DEBUG ("Generate DIV for CSRK"); + p_cb->rand_enc_proc_state = SMP_GEN_DIV_CSRK; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } + } +} + +/******************************************************************************* +** Function smp_concatenate_peer +** add pairing command sent from local device into p1. +*******************************************************************************/ +void smp_concatenate_local( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code) +{ + UINT8 *p = *p_data; + + SMP_TRACE_DEBUG ("%s\n", __func__); + UINT8_TO_STREAM(p, op_code); + UINT8_TO_STREAM(p, p_cb->local_io_capability); + UINT8_TO_STREAM(p, p_cb->loc_oob_flag); + UINT8_TO_STREAM(p, p_cb->loc_auth_req); + UINT8_TO_STREAM(p, p_cb->loc_enc_size); + UINT8_TO_STREAM(p, p_cb->local_i_key); + UINT8_TO_STREAM(p, p_cb->local_r_key); + + *p_data = p; +} + +/******************************************************************************* +** Function smp_concatenate_peer +** add pairing command received from peer device into p1. +*******************************************************************************/ +void smp_concatenate_peer( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code) +{ + UINT8 *p = *p_data; + + SMP_TRACE_DEBUG ("smp_concatenate_peer \n"); + UINT8_TO_STREAM(p, op_code); + UINT8_TO_STREAM(p, p_cb->peer_io_caps); + UINT8_TO_STREAM(p, p_cb->peer_oob_flag); + UINT8_TO_STREAM(p, p_cb->peer_auth_req); + UINT8_TO_STREAM(p, p_cb->peer_enc_size); + UINT8_TO_STREAM(p, p_cb->peer_i_key); + UINT8_TO_STREAM(p, p_cb->peer_r_key); + + *p_data = p; +} + +/******************************************************************************* +** +** Function smp_gen_p1_4_confirm +** +** Description Generate Confirm/Compare Step1: +** p1 = pres || preq || rat' || iat' +** +** Returns void +** +*******************************************************************************/ +void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1) +{ + UINT8 *p = (UINT8 *)p1; + tBLE_ADDR_TYPE addr_type = 0; + BD_ADDR remote_bda; + + SMP_TRACE_DEBUG ("smp_gen_p1_4_confirm\n"); + + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type)) { + SMP_TRACE_ERROR("can not generate confirm for unknown device\n"); + return; + } + + BTM_ReadConnectionAddr( p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type); + + if (p_cb->role == HCI_ROLE_MASTER) { + /* LSB : rat': initiator's(local) address type */ + UINT8_TO_STREAM(p, p_cb->addr_type); + /* LSB : iat': responder's address type */ + UINT8_TO_STREAM(p, addr_type); + /* concatinate preq */ + smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ); + /* concatinate pres */ + smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_RSP); + } else { + /* LSB : iat': initiator's address type */ + UINT8_TO_STREAM(p, addr_type); + /* LSB : rat': responder's(local) address type */ + UINT8_TO_STREAM(p, p_cb->addr_type); + /* concatinate preq */ + smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ); + /* concatinate pres */ + smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP); + } +#if SMP_DEBUG == TRUE + SMP_TRACE_DEBUG("p1 = pres || preq || rat' || iat'\n"); + smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1", 16); +#endif +} + +/******************************************************************************* +** +** Function smp_gen_p2_4_confirm +** +** Description Generate Confirm/Compare Step2: +** p2 = padding || ia || ra +** +** Returns void +** +*******************************************************************************/ +void smp_gen_p2_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p2) +{ + UINT8 *p = (UINT8 *)p2; + BD_ADDR remote_bda; + tBLE_ADDR_TYPE addr_type = 0; + SMP_TRACE_DEBUG ("smp_gen_p2_4_confirm\n"); + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type)) { + SMP_TRACE_ERROR("can not generate confirm p2 for unknown device\n"); + return; + } + + SMP_TRACE_DEBUG ("smp_gen_p2_4_confirm\n"); + + memset(p, 0, sizeof(BT_OCTET16)); + + if (p_cb->role == HCI_ROLE_MASTER) { + /* LSB ra */ + BDADDR_TO_STREAM(p, remote_bda); + /* ia */ + BDADDR_TO_STREAM(p, p_cb->local_bda); + } else { + /* LSB ra */ + BDADDR_TO_STREAM(p, p_cb->local_bda); + /* ia */ + BDADDR_TO_STREAM(p, remote_bda); + } +#if SMP_DEBUG == TRUE + SMP_TRACE_DEBUG("p2 = padding || ia || ra"); + smp_debug_print_nbyte_little_endian(p2, (const UINT8 *)"p2", 16); +#endif +} + +/******************************************************************************* +** +** Function smp_calculate_comfirm +** +** Description This function is called to calculate Confirm value. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_comfirm (tSMP_CB *p_cb, BT_OCTET16 rand, BD_ADDR bda) +{ + UNUSED(bda); + + BT_OCTET16 p1; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("smp_calculate_comfirm \n"); + /* generate p1 = pres || preq || rat' || iat' */ + smp_gen_p1_4_confirm(p_cb, p1); + + /* p1 = rand XOR p1 */ + smp_xor_128(p1, rand); + + smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1' = r XOR p1", 16); + + /* calculate e(k, r XOR p1), where k = TK */ + if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, &output)) { + SMP_TRACE_ERROR("smp_generate_csrk failed"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } else { + smp_calculate_comfirm_cont(p_cb, &output); + } +} + +/******************************************************************************* +** +** Function smp_calculate_comfirm_cont +** +** Description This function is called when SConfirm/MConfirm is generated +** proceed to send the Confirm request/response to peer device. +** +** Returns void +** +*******************************************************************************/ +static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p) +{ + BT_OCTET16 p2; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("smp_calculate_comfirm_cont \n"); +#if SMP_DEBUG == TRUE + SMP_TRACE_DEBUG("Confirm step 1 p1' = e(k, r XOR p1) Generated\n"); + smp_debug_print_nbyte_little_endian (p->param_buf, (const UINT8 *)"C1", 16); +#endif + + smp_gen_p2_4_confirm(p_cb, p2); + + /* calculate p2 = (p1' XOR p2) */ + smp_xor_128(p2, p->param_buf); + smp_debug_print_nbyte_little_endian ((UINT8 *)p2, (const UINT8 *)"p2' = C1 xor p2", 16); + + /* calculate: Confirm = E(k, p1' XOR p2) */ + if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p2, BT_OCTET16_LEN, &output)) { + SMP_TRACE_ERROR("smp_calculate_comfirm_cont failed\n"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } else { + SMP_TRACE_DEBUG("p_cb->rand_enc_proc_state=%d\n", p_cb->rand_enc_proc_state); + switch (p_cb->rand_enc_proc_state) { + case SMP_GEN_CONFIRM: + smp_process_confirm(p_cb, &output); + break; + + case SMP_GEN_COMPARE: + smp_process_compare(p_cb, &output); + break; + } + } +} + +/******************************************************************************* +** +** Function smp_generate_confirm +** +** Description This function is called when a 48 bits random number is generated +** as SRand or MRand, continue to calculate Sconfirm or MConfirm. +** +** Returns void +** +*******************************************************************************/ +static void smp_generate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("%s\n", __func__); + p_cb->rand_enc_proc_state = SMP_GEN_CONFIRM; + smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->rand, (const UINT8 *)"local rand", 16); + smp_calculate_comfirm(p_cb, p_cb->rand, p_cb->pairing_bda); +} + +/******************************************************************************* +** +** Function smp_generate_compare +** +** Description This function is called to generate SConfirm for Slave device, +** or MSlave for Master device. This function can be also used for +** generating Compare number for confirm value check. +** +** Returns void +** +*******************************************************************************/ +void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + SMP_TRACE_DEBUG ("smp_generate_compare \n"); + p_cb->rand_enc_proc_state = SMP_GEN_COMPARE; + smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->rrand, (const UINT8 *)"peer rand", 16); + smp_calculate_comfirm(p_cb, p_cb->rrand, p_cb->local_bda); +} + +/******************************************************************************* +** +** Function smp_process_confirm +** +** Description This function is called when SConfirm/MConfirm is generated +** proceed to send the Confirm request/response to peer device. +** +** Returns void +** +*******************************************************************************/ +static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p) +{ + tSMP_KEY key; + + SMP_TRACE_DEBUG ("%s\n", __FUNCTION__); + memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN); + +#if (SMP_DEBUG == TRUE) + SMP_TRACE_DEBUG("Confirm Generated"); + smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->confirm, (const UINT8 *)"Confirm", 16); +#endif + + key.key_type = SMP_KEY_TYPE_CFM; + key.p_data = p->param_buf; + + smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key); + +} + +/******************************************************************************* +** +** Function smp_process_compare +** +** Description This function is called when Compare is generated using the +** RRand and local BDA, TK information. +** +** Returns void +** +*******************************************************************************/ +static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p) +{ + tSMP_KEY key; + + SMP_TRACE_DEBUG ("smp_process_compare \n"); +#if (SMP_DEBUG == TRUE) + SMP_TRACE_DEBUG("Compare Generated\n"); + smp_debug_print_nbyte_little_endian (p->param_buf, (const UINT8 *)"Compare", 16); +#endif + key.key_type = SMP_KEY_TYPE_CMP; + key.p_data = p->param_buf; + //smp_set_state(SMP_STATE_CONFIRM); + smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_process_stk +** +** Description This function is called when STK is generated +** proceed to send the encrypt the link using STK. +** +** Returns void +** +*******************************************************************************/ +static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p) +{ + tSMP_KEY key; + + SMP_TRACE_DEBUG ("smp_process_stk "); +#if (SMP_DEBUG == TRUE) + SMP_TRACE_ERROR("STK Generated"); +#endif + smp_mask_enc_key(p_cb->loc_enc_size, p->param_buf); + + key.key_type = SMP_KEY_TYPE_STK; + key.p_data = p->param_buf; + + smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_generate_ltk_cont +** +** Description This function is to calculate LTK = d1(ER, DIV, 0)= e(ER, DIV) +** +** Returns void +** +*******************************************************************************/ +static void smp_generate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UNUSED(p_data); + + BT_OCTET16 er; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("%s\n", __func__); + BTM_GetDeviceEncRoot(er); + + /* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/ + if (!SMP_Encrypt(er, BT_OCTET16_LEN, (UINT8 *)&p_cb->div, + sizeof(UINT16), &output)) { + SMP_TRACE_ERROR("%s failed\n", __func__); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } else { + /* mask the LTK */ + smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf); + memcpy((void *)p_cb->ltk, output.param_buf, BT_OCTET16_LEN); + smp_generate_rand_vector(p_cb, NULL); + } +} + +/******************************************************************************* +** +** Function smp_generate_y +** +** Description This function is to proceed generate Y = E(DHK, Rand) +** +** Returns void +** +*******************************************************************************/ +static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p) +{ + UNUSED(p); + + BT_OCTET16 dhk; + tSMP_ENC output; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + + SMP_TRACE_DEBUG ("smp_generate_y \n"); + BTM_GetDeviceDHK(dhk); + + if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, p_cb->enc_rand, + BT_OCTET8_LEN, &output)) { + SMP_TRACE_ERROR("smp_generate_y failed"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } else { + smp_process_ediv(p_cb, &output); + } +} + +/******************************************************************************* +** +** Function smp_generate_rand_vector +** +** Description This function is called when LTK is generated, send state machine +** event to SMP. +** +** Returns void +** +*******************************************************************************/ +static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p) +{ + UNUSED(p); + + /* generate EDIV and rand now */ + /* generate random vector */ + SMP_TRACE_DEBUG ("smp_generate_rand_vector\n"); + p_cb->rand_enc_proc_state = SMP_GEN_RAND_V; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** +** Function smp_process_ediv +** +** Description This function is to calculate EDIV = Y xor DIV +** +** Returns void +** +*******************************************************************************/ +static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p) +{ + tSMP_KEY key; + UINT8 *pp = p->param_buf; + UINT16 y; + + SMP_TRACE_DEBUG ("smp_process_ediv "); + STREAM_TO_UINT16(y, pp); + + /* EDIV = Y xor DIV */ + p_cb->ediv = p_cb->div ^ y; + /* send LTK ready */ + SMP_TRACE_DEBUG("LTK ready"); + key.key_type = SMP_KEY_TYPE_LTK; + key.p_data = p->param_buf; + + smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_calculate_legacy_short_term_key +** +** Description The function calculates legacy STK. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +*******************************************************************************/ +BOOLEAN smp_calculate_legacy_short_term_key(tSMP_CB *p_cb, tSMP_ENC *output) +{ + BT_OCTET16 ptext; + UINT8 *p = ptext; + + SMP_TRACE_DEBUG ("%s\n", __func__); + memset(p, 0, BT_OCTET16_LEN); + if (p_cb->role == HCI_ROLE_MASTER) { + memcpy(p, p_cb->rand, BT_OCTET8_LEN); + memcpy(&p[BT_OCTET8_LEN], p_cb->rrand, BT_OCTET8_LEN); + } else { + memcpy(p, p_cb->rrand, BT_OCTET8_LEN); + memcpy(&p[BT_OCTET8_LEN], p_cb->rand, BT_OCTET8_LEN); + } + + BOOLEAN encrypted; + /* generate STK = Etk(rand|rrand)*/ + encrypted = SMP_Encrypt( p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, output); + if (!encrypted) { + SMP_TRACE_ERROR("%s failed\n", __func__); + } + return encrypted; +} + +/******************************************************************************* +** +** Function smp_create_private_key +** +** Description This function is called to create private key used to +** calculate public key and DHKey. +** The function starts private key creation requesting controller +** to generate [0-7] octets of private key. +** +** Returns void +** +*******************************************************************************/ +void smp_create_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG("%s", __func__); + + if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) { + SMP_TRACE_EVENT("OOB Association Model"); + if (!oob_data_is_empty(&saved_local_oob_data)) { + SMP_TRACE_EVENT("Found OOB data, loading keys"); + memcpy(&p_cb->sc_oob_data.loc_oob_data, &saved_local_oob_data, sizeof(tSMP_LOC_OOB_DATA)); + smp_process_private_key(p_cb); + return; + } + SMP_TRACE_EVENT("OOB Association Model with no saved data"); + } + + p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_0_7; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** +** Function smp_use_oob_private_key +** +** Description This function is called +** - to save the secret key used to calculate the public key used +** in calculations of commitment sent OOB to a peer +** - to use this secret key to recalculate the public key and +** start the process of sending this public key to the peer +** if secret/public keys have to be reused. +** If the keys aren't supposed to be reused, continue from the +** point from which request for OOB data was issued. +** +** Returns void +** +*******************************************************************************/ +void smp_use_oob_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG ("%s req_oob_type: %d, role: %d\n", + __func__, p_cb->req_oob_type, p_cb->role); + + switch (p_cb->req_oob_type) { + case SMP_OOB_BOTH: + case SMP_OOB_LOCAL: + SMP_TRACE_DEBUG("%s restore secret key\n", __func__); + // copy private key in smp_process_private_key + smp_process_private_key(p_cb); + break; + default: + SMP_TRACE_DEBUG("%s create secret key anew\n", __func__); + smp_set_state(SMP_STATE_PAIR_REQ_RSP); + smp_decide_association_model(p_cb, NULL); + break; + } +} + +/******************************************************************************* +** +** Function smp_continue_private_key_creation +** +** Description This function is used to continue private key creation. +** +** Returns void +** +*******************************************************************************/ +void smp_continue_private_key_creation (tSMP_CB *p_cb, tBTM_RAND_ENC *p) +{ + UINT8 state = p_cb->rand_enc_proc_state & ~0x80; + SMP_TRACE_DEBUG ("%s state=0x%x\n", __func__, state); + + switch (state) { + case SMP_GENERATE_PRIVATE_KEY_0_7: + memcpy((void *)p_cb->private_key, p->param_buf, p->param_len); + p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_8_15; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } + break; + + case SMP_GENERATE_PRIVATE_KEY_8_15: + memcpy((void *)&p_cb->private_key[8], p->param_buf, p->param_len); + p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_16_23; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } + break; + + case SMP_GENERATE_PRIVATE_KEY_16_23: + memcpy((void *)&p_cb->private_key[16], p->param_buf, p->param_len); + p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_24_31; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } + break; + + case SMP_GENERATE_PRIVATE_KEY_24_31: + memcpy((void *)&p_cb->private_key[24], p->param_buf, p->param_len); + smp_process_private_key (p_cb); + break; + + default: + break; + } + + return; +} + +/******************************************************************************* +** +** Function smp_process_private_key +** +** Description This function processes private key. +** It calculates public key and notifies SM that private key / +** public key pair is created. +** +** Returns void +** +*******************************************************************************/ +void smp_process_private_key(tSMP_CB *p_cb) +{ + Point public_key; + BT_OCTET32 private_key; + tSMP_LOC_OOB_DATA *p_loc_oob = &p_cb->sc_oob_data.loc_oob_data; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + /* if local oob data present, then restore oob private and public key */ + if (p_loc_oob->present) { + memcpy(p_cb->private_key, p_loc_oob->private_key_used, BT_OCTET32_LEN); + memcpy(p_cb->loc_publ_key.x, p_loc_oob->publ_key_used.x, BT_OCTET32_LEN); + memcpy(p_cb->loc_publ_key.y, p_loc_oob->publ_key_used.y, BT_OCTET32_LEN); + memcpy(p_cb->local_random, p_loc_oob->randomizer, BT_OCTET16_LEN); + } else { + memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN); + ECC_PointMult(&public_key, &(curve_p256.G), (DWORD *) private_key, KEY_LENGTH_DWORDS_P256); + memcpy(p_cb->loc_publ_key.x, public_key.x, BT_OCTET32_LEN); + memcpy(p_cb->loc_publ_key.y, public_key.y, BT_OCTET32_LEN); + } + + smp_debug_print_nbyte_little_endian (p_cb->private_key, (const UINT8 *)"private", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->loc_publ_key.x, (const UINT8 *)"local public(x)", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->loc_publ_key.y, (const UINT8 *)"local public(y)", + BT_OCTET32_LEN); + p_cb->flags |= SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY; + smp_sm_event(p_cb, SMP_LOC_PUBL_KEY_CRTD_EVT, NULL); +} + +/******************************************************************************* +** +** Function smp_compute_dhkey +** +** Description The function: +** - calculates a new public key using as input local private +** key and peer public key; +** - saves the new public key x-coordinate as DHKey. +** +** Returns void +** +*******************************************************************************/ +void smp_compute_dhkey (tSMP_CB *p_cb) +{ + Point peer_publ_key, new_publ_key; + BT_OCTET32 private_key; + + SMP_TRACE_DEBUG ("%s\n", __FUNCTION__); + + memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN); + memcpy(peer_publ_key.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN); + memcpy(peer_publ_key.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN); + + ECC_PointMult(&new_publ_key, &peer_publ_key, (DWORD *) private_key, KEY_LENGTH_DWORDS_P256); + + memcpy(p_cb->dhkey, new_publ_key.x, BT_OCTET32_LEN); + + smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"Old DHKey", + BT_OCTET32_LEN); + + smp_debug_print_nbyte_little_endian (p_cb->private_key, (const UINT8 *)"private", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.x, (const UINT8 *)"rem public(x)", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.y, (const UINT8 *)"rem public(y)", + BT_OCTET32_LEN); + smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"Reverted DHKey", + BT_OCTET32_LEN); +} + +/******************************************************************************* +** +** Function smp_calculate_local_commitment +** +** Description The function calculates and saves local commmitment in CB. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_local_commitment(tSMP_CB *p_cb) +{ + UINT8 random_input; + + SMP_TRACE_DEBUG("%s\n", __FUNCTION__); + + switch (p_cb->selected_association_model) { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + if (p_cb->role == HCI_ROLE_MASTER) { + SMP_TRACE_WARNING ("local commitment calc on master is not expected \ + for Just Works/Numeric Comparison models\n"); + } + smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, 0, + p_cb->commitment); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + random_input = smp_calculate_random_input(p_cb->local_random, p_cb->round); + smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, + random_input, p_cb->commitment); + break; + case SMP_MODEL_SEC_CONN_OOB: + SMP_TRACE_WARNING ("local commitment calc is expected for OOB model BEFORE pairing\n"); + smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->loc_publ_key.x, p_cb->local_random, 0, + p_cb->commitment); + break; + default: + SMP_TRACE_ERROR("Association Model = %d is not used in LE SC\n", + p_cb->selected_association_model); + return; + } + + SMP_TRACE_EVENT ("local commitment calculation is completed"); +} + +/******************************************************************************* +** +** Function smp_calculate_peer_commitment +** +** Description The function calculates and saves peer commmitment at the +** provided output buffer. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_peer_commitment(tSMP_CB *p_cb, BT_OCTET16 output_buf) +{ + UINT8 ri; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + switch (p_cb->selected_association_model) { + case SMP_MODEL_SEC_CONN_JUSTWORKS: + case SMP_MODEL_SEC_CONN_NUM_COMP: + if (p_cb->role == HCI_ROLE_SLAVE) { + SMP_TRACE_WARNING ("peer commitment calc on slave is not expected \ + for Just Works/Numeric Comparison models\n"); + } + smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, 0, + output_buf); + break; + case SMP_MODEL_SEC_CONN_PASSKEY_ENT: + case SMP_MODEL_SEC_CONN_PASSKEY_DISP: + ri = smp_calculate_random_input(p_cb->peer_random, p_cb->round); + smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, ri, + output_buf); + break; + case SMP_MODEL_SEC_CONN_OOB: + smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x, p_cb->peer_random, 0, + output_buf); + break; + default: + SMP_TRACE_ERROR("Association Model = %d is not used in LE SC\n", + p_cb->selected_association_model); + return; + } + + SMP_TRACE_EVENT ("peer commitment calculation is completed\n"); +} + +/******************************************************************************* +** +** Function smp_calculate_f4 +** +** Description The function calculates +** C = f4(U, V, X, Z) = AES-CMAC (U||V||Z) +** X +** where +** input: U is 256 bit, +** V is 256 bit, +** X is 128 bit, +** Z is 8 bit, +** output: C is 128 bit. +** +** Returns void +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +void smp_calculate_f4(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 z, UINT8 *c) +{ + UINT8 msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ + 1 /* Z size */; + UINT8 msg[BT_OCTET32_LEN + BT_OCTET32_LEN + 1]; + UINT8 key[BT_OCTET16_LEN]; + UINT8 cmac[BT_OCTET16_LEN]; + UINT8 *p = NULL; +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + +#if SMP_DEBUG == TRUE + p_prnt = u; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"U", BT_OCTET32_LEN); + p_prnt = v; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"V", BT_OCTET32_LEN); + p_prnt = x; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"X", BT_OCTET16_LEN); + p_prnt = &z; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Z", 1); +#endif + + p = msg; + UINT8_TO_STREAM(p, z); + ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN); + ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN); +#if SMP_DEBUG == TRUE + p_prnt = msg; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", msg_len); +#endif + + p = key; + ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_prnt = key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + + aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac); +#if SMP_DEBUG == TRUE + p_prnt = cmac; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES_CMAC", BT_OCTET16_LEN); +#endif + + p = c; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); +} + +/******************************************************************************* +** +** Function smp_calculate_numeric_comparison_display_number +** +** Description The function calculates and saves number to display in numeric +** comparison association mode. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_numeric_comparison_display_number(tSMP_CB *p_cb, + tSMP_INT_DATA *p_data) +{ + SMP_TRACE_DEBUG ("%s", __func__); + + if (p_cb->role == HCI_ROLE_MASTER) { + p_cb->number_to_display = + smp_calculate_g2(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, + p_cb->rrand); + } else { + p_cb->number_to_display = + smp_calculate_g2(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, + p_cb->rand); + } + + if (p_cb->number_to_display >= (BTM_MAX_PASSKEY_VAL + 1)) { + UINT8 reason; + reason = p_cb->failure = SMP_PAIR_FAIL_UNKNOWN; + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + return; + } + + SMP_TRACE_EVENT("Number to display in numeric comparison = %d", p_cb->number_to_display); + p_cb->cb_evt = SMP_NC_REQ_EVT; + smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, &p_cb->number_to_display); + return; +} + +/******************************************************************************* +** +** Function smp_calculate_g2 +** +** Description The function calculates +** g2(U, V, X, Y) = AES-CMAC (U||V||Y) mod 2**32 mod 10**6 +** X +** and +** Vres = g2(U, V, X, Y) mod 10**6 +** where +** input: U is 256 bit, +** V is 256 bit, +** X is 128 bit, +** Y is 128 bit, +** +** Returns Vres. +** Expected value has to be in the range [0 - 999999] i.e. [0 - 0xF423F]. +** Vres = 1000000 means that the calculation fails. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +UINT32 smp_calculate_g2(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 *y) +{ + UINT8 msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ + + BT_OCTET16_LEN /* Y size */; + UINT8 msg[BT_OCTET32_LEN + BT_OCTET32_LEN + BT_OCTET16_LEN]; + UINT8 key[BT_OCTET16_LEN]; + UINT8 cmac[BT_OCTET16_LEN]; + UINT8 *p = NULL; + UINT32 vres; +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + + SMP_TRACE_DEBUG ("%s\n", __FUNCTION__); + + p = msg; + ARRAY_TO_STREAM(p, y, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN); + ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN); +#if SMP_DEBUG == TRUE + p_prnt = u; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"U", BT_OCTET32_LEN); + p_prnt = v; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"V", BT_OCTET32_LEN); + p_prnt = x; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"X", BT_OCTET16_LEN); + p_prnt = y; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Y", BT_OCTET16_LEN); +#endif + + p = key; + ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_prnt = key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + + if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + return (BTM_MAX_PASSKEY_VAL + 1); + } + +#if SMP_DEBUG == TRUE + p_prnt = cmac; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + /* vres = cmac mod 2**32 mod 10**6 */ + p = &cmac[0]; + STREAM_TO_UINT32(vres, p); +#if SMP_DEBUG == TRUE + p_prnt = (UINT8 *) &vres; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"cmac mod 2**32", 4); +#endif + + while (vres > BTM_MAX_PASSKEY_VAL) { + vres -= (BTM_MAX_PASSKEY_VAL + 1); + } +#if SMP_DEBUG == TRUE + p_prnt = (UINT8 *) &vres; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"cmac mod 2**32 mod 10**6", 4); +#endif + + SMP_TRACE_ERROR("Value for numeric comparison = %d", vres); + return vres; +} + +/******************************************************************************* +** +** Function smp_calculate_f5 +** +** Description The function provides two AES-CMAC that are supposed to be used as +** - MacKey (MacKey is used in pairing DHKey check calculation); +** - LTK (LTK is used to ecrypt the link after completion of Phase 2 +** and on reconnection, to derive BR/EDR LK). +** The function inputs are W, N1, N2, A1, A2. +** F5 rules: +** - the value used as key in MacKey/LTK (T) is calculated +** (function smp_calculate_f5_key(...)); +** The formula is: +** T = AES-CMAC (W) +** salt +** where salt is internal parameter of smp_calculate_f5_key(...). +** - MacKey and LTK are calculated as AES-MAC values received with the +** key T calculated in the previous step and the plaintext message +** built from the external parameters N1, N2, A1, A2 and the internal +** parameters counter, keyID, length. +** The function smp_calculate_f5_mackey_or_long_term_key(...) is used in the +** calculations. +** The same formula is used in calculation of MacKey and LTK and the +** same parameter values except the value of the internal parameter +** counter: +** - in MacKey calculations the value is 0; +** - in LTK calculations the value is 1. +** MacKey = AES-CMAC (Counter=0||keyID||N1||N2||A1||A2||Length=256) +** T +** LTK = AES-CMAC (Counter=1||keyID||N1||N2||A1||A2||Length=256) +** T +** The parameters are +** input: +** W is 256 bits, +** N1 is 128 bits, +** N2 is 128 bits, +** A1 is 56 bit, +** A2 is 56 bit. +** internal: +** Counter is 8 bits, its value is 0 for MacKey, +** 1 for LTK; +** KeyId is 32 bits, its value is +** 0x62746c65 (MSB~LSB); +** Length is 16 bits, its value is 0x0100 +** (MSB~LSB). +** output: +** MacKey is 128 bits; +** LTK is 128 bits +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f5(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *mac_key, UINT8 *ltk) +{ + BT_OCTET16 t; /* AES-CMAC output in smp_calculate_f5_key(...), key in */ + /* smp_calculate_f5_mackey_or_long_term_key(...) */ +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + /* internal parameters: */ + + /* + counter is 0 for MacKey, + is 1 for LTK + */ + UINT8 counter_mac_key[1] = {0}; + UINT8 counter_ltk[1] = {1}; + /* + keyID 62746c65 + */ + UINT8 key_id[4] = {0x65, 0x6c, 0x74, 0x62}; + /* + length 0100 + */ + UINT8 length[2] = {0x00, 0x01}; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_prnt = w; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"W", BT_OCTET32_LEN); + p_prnt = n1; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N1", BT_OCTET16_LEN); + p_prnt = n2; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N2", BT_OCTET16_LEN); + p_prnt = a1; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A1", 7); + p_prnt = a2; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *) "A2", 7); +#endif + + if (!smp_calculate_f5_key(w, t)) { + SMP_TRACE_ERROR("%s failed to calc T", __FUNCTION__); + return FALSE; + } +#if SMP_DEBUG == TRUE + p_prnt = t; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"T", BT_OCTET16_LEN); +#endif + + if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_mac_key, key_id, n1, n2, a1, a2, + length, mac_key)) { + SMP_TRACE_ERROR("%s failed to calc MacKey", __FUNCTION__); + return FALSE; + } +#if SMP_DEBUG == TRUE + p_prnt = mac_key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"MacKey", BT_OCTET16_LEN); +#endif + + if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_ltk, key_id, n1, n2, a1, a2, + length, ltk)) { + SMP_TRACE_ERROR("%s failed to calc LTK", __FUNCTION__); + return FALSE; + } +#if SMP_DEBUG == TRUE + p_prnt = ltk; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"LTK", BT_OCTET16_LEN); +#endif + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_calculate_f5_mackey_or_long_term_key +** +** Description The function calculates the value of MacKey or LTK by the rules +** defined for f5 function. +** At the moment exactly the same formula is used to calculate +** LTK and MacKey. +** The difference is the value of input parameter Counter: +** - in MacKey calculations the value is 0; +** - in LTK calculations the value is 1. +** The formula: +** mac = AES-CMAC (Counter||keyID||N1||N2||A1||A2||Length) +** T +** where +** input: T is 256 bits; +** Counter is 8 bits, its value is 0 for MacKey, +** 1 for LTK; +** keyID is 32 bits, its value is 0x62746c65; +** N1 is 128 bits; +** N2 is 128 bits; +** A1 is 56 bits; +** A2 is 56 bits; +** Length is 16 bits, its value is 0x0100 +** output: LTK is 128 bit. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f5_mackey_or_long_term_key(UINT8 *t, UINT8 *counter, + UINT8 *key_id, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2, + UINT8 *length, UINT8 *mac) +{ + UINT8 *p = NULL; + UINT8 cmac[BT_OCTET16_LEN]; + UINT8 key[BT_OCTET16_LEN]; + UINT8 msg_len = 1 /* Counter size */ + 4 /* keyID size */ + + BT_OCTET16_LEN /* N1 size */ + BT_OCTET16_LEN /* N2 size */ + + 7 /* A1 size*/ + 7 /* A2 size*/ + 2 /* Length size */; + UINT8 msg[1 + 4 + BT_OCTET16_LEN + BT_OCTET16_LEN + 7 + 7 + 2]; + BOOLEAN ret = TRUE; +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_prnt = t; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"T", BT_OCTET16_LEN); + p_prnt = counter; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Counter", 1); + p_prnt = key_id; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"KeyID", 4); + p_prnt = n1; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N1", BT_OCTET16_LEN); + p_prnt = n2; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N2", BT_OCTET16_LEN); + p_prnt = a1; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A1", 7); + p_prnt = a2; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A2", 7); + p_prnt = length; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Length", 2); +#endif + + p = key; + ARRAY_TO_STREAM(p, t, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_prnt = key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + p = msg; + ARRAY_TO_STREAM(p, length, 2); + ARRAY_TO_STREAM(p, a2, 7); + ARRAY_TO_STREAM(p, a1, 7); + ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, key_id, 4); + ARRAY_TO_STREAM(p, counter, 1); +#if SMP_DEBUG == TRUE + p_prnt = msg; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", msg_len); +#endif + + if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + ret = FALSE; + } + +#if SMP_DEBUG == TRUE + p_prnt = cmac; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + p = mac; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_f5_key +** +** Description The function calculates key T used in calculation of +** MacKey and LTK (f5 output is defined as MacKey || LTK). +** T = AES-CMAC (W) +** salt +** where +** Internal: salt is 128 bit. +** input: W is 256 bit. +** Output: T is 128 bit. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f5_key(UINT8 *w, UINT8 *t) +{ + UINT8 *p = NULL; + /* Please see 2.2.7 LE Secure Connections Key Generation Function f5 */ + /* + salt: 6C88 8391 AAF5 A538 6037 0BDB 5A60 83BE + */ + BT_OCTET16 salt = { + 0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60, + 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C + }; +#if SMP_DEBUG == TRUE + UINT8 *p_prnt = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_prnt = salt; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"salt", BT_OCTET16_LEN); + p_prnt = w; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"W", BT_OCTET32_LEN); +#endif + + BT_OCTET16 key; + BT_OCTET32 msg; + + p = key; + ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN); + p = msg; + ARRAY_TO_STREAM(p, w, BT_OCTET32_LEN); +#if SMP_DEBUG == TRUE + p_prnt = key; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN); + p_prnt = msg; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", BT_OCTET32_LEN); +#endif + + BT_OCTET16 cmac; + BOOLEAN ret = TRUE; + if (!aes_cipher_msg_auth_code(key, msg, BT_OCTET32_LEN, BT_OCTET16_LEN, cmac)) { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + ret = FALSE; + } + +#if SMP_DEBUG == TRUE + p_prnt = cmac; + smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + p = t; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_local_dhkey_check +** +** Description The function calculates and saves local device DHKey check +** value in CB. +** Before doing this it calls smp_calculate_f5_mackey_and_long_term_key(...). +** to calculate MacKey and LTK. +** MacKey is used in dhkey calculation. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_local_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 iocap[3], a[7], b[7]; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + smp_calculate_f5_mackey_and_long_term_key(p_cb); + + smp_collect_local_io_capabilities(iocap, p_cb); + + smp_collect_local_ble_address(a, p_cb); + smp_collect_peer_ble_address(b, p_cb); + smp_calculate_f6(p_cb->mac_key, p_cb->rand, p_cb->rrand, p_cb->peer_random, iocap, a, b, + p_cb->dhkey_check); + + SMP_TRACE_EVENT ("local DHKey check calculation is completed"); +} + +/******************************************************************************* +** +** Function smp_calculate_peer_dhkey_check +** +** Description The function calculates peer device DHKey check value. +** +** Returns void +** +*******************************************************************************/ +void smp_calculate_peer_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) +{ + UINT8 iocap[3], a[7], b[7]; + BT_OCTET16 param_buf; + BOOLEAN ret; + tSMP_KEY key; + tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + smp_collect_peer_io_capabilities(iocap, p_cb); + + smp_collect_local_ble_address(a, p_cb); + smp_collect_peer_ble_address(b, p_cb); + ret = smp_calculate_f6(p_cb->mac_key, p_cb->rrand, p_cb->rand, p_cb->local_random, iocap, + b, a, param_buf); + + if (ret) { + SMP_TRACE_EVENT ("peer DHKey check calculation is completed"); +#if (SMP_DEBUG == TRUE) + smp_debug_print_nbyte_little_endian (param_buf, (const UINT8 *)"peer DHKey check", + BT_OCTET16_LEN); +#endif + key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK; + key.p_data = param_buf; + smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &key); + } else { + SMP_TRACE_EVENT ("peer DHKey check calculation failed"); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status); + } +} + +/******************************************************************************* +** +** Function smp_calculate_f6 +** +** Description The function calculates +** C = f6(W, N1, N2, R, IOcap, A1, A2) = AES-CMAC (N1||N2||R||IOcap||A1||A2) +** W +** where +** input: W is 128 bit, +** N1 is 128 bit, +** N2 is 128 bit, +** R is 128 bit, +** IOcap is 24 bit, +** A1 is 56 bit, +** A2 is 56 bit, +** output: C is 128 bit. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f6(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, UINT8 *iocap, UINT8 *a1, + UINT8 *a2, UINT8 *c) +{ + UINT8 *p = NULL; + UINT8 msg_len = BT_OCTET16_LEN /* N1 size */ + BT_OCTET16_LEN /* N2 size */ + + BT_OCTET16_LEN /* R size */ + 3 /* IOcap size */ + 7 /* A1 size*/ + + 7 /* A2 size*/; + UINT8 msg[BT_OCTET16_LEN + BT_OCTET16_LEN + BT_OCTET16_LEN + 3 + 7 + 7]; +#if SMP_DEBUG == TRUE + UINT8 *p_print = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_print = w; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"W", BT_OCTET16_LEN); + p_print = n1; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"N1", BT_OCTET16_LEN); + p_print = n2; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"N2", BT_OCTET16_LEN); + p_print = r; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"R", BT_OCTET16_LEN); + p_print = iocap; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"IOcap", 3); + p_print = a1; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"A1", 7); + p_print = a2; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"A2", 7); +#endif + + UINT8 cmac[BT_OCTET16_LEN]; + UINT8 key[BT_OCTET16_LEN]; + + p = key; + ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_print = key; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + + p = msg; + ARRAY_TO_STREAM(p, a2, 7); + ARRAY_TO_STREAM(p, a1, 7); + ARRAY_TO_STREAM(p, iocap, 3); + ARRAY_TO_STREAM(p, r, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN); + ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN); +#if SMP_DEBUG == TRUE + p_print = msg; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"M", msg_len); +#endif + + BOOLEAN ret = TRUE; + if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + ret = FALSE; + } + +#if SMP_DEBUG == TRUE + p_print = cmac; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + p = c; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_link_key_from_long_term_key +** +** Description The function calculates and saves BR/EDR link key derived from +** LE SC LTK. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +*******************************************************************************/ +BOOLEAN smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + BD_ADDR bda_for_lk; + tBLE_ADDR_TYPE conn_addr_type; + + SMP_TRACE_DEBUG ("%s", __func__); + + if (p_cb->id_addr_rcvd && p_cb->id_addr_type == BLE_ADDR_PUBLIC) { + SMP_TRACE_DEBUG ("Use rcvd identity address as BD_ADDR of LK rcvd identity address"); + memcpy(bda_for_lk, p_cb->id_addr, BD_ADDR_LEN); + } else if ((BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda_for_lk, &conn_addr_type)) && + conn_addr_type == BLE_ADDR_PUBLIC) { + SMP_TRACE_DEBUG ("Use rcvd connection address as BD_ADDR of LK"); + } else { + SMP_TRACE_WARNING ("Don't have peer public address to associate with LK"); + return FALSE; + } + + if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL) { + SMP_TRACE_ERROR("%s failed to find Security Record", __func__); + return FALSE; + } + + BT_OCTET16 intermediate_link_key; + BOOLEAN ret = TRUE; + + ret = smp_calculate_h6(p_cb->ltk, (UINT8 *)"1pmt" /* reversed "tmp1" */, intermediate_link_key); + if (!ret) { + SMP_TRACE_ERROR("%s failed to derive intermediate_link_key", __func__); + return ret; + } + + BT_OCTET16 link_key; + ret = smp_calculate_h6(intermediate_link_key, (UINT8 *) "rbel" /* reversed "lebr" */, link_key); + if (!ret) { + SMP_TRACE_ERROR("%s failed", __func__); + } else { + UINT8 link_key_type; + if (btm_cb.security_mode == BTM_SEC_MODE_SC) { + /* Secure Connections Only Mode */ + link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256; + } else if (controller_get_interface()->supports_secure_connections()) { + /* both transports are SC capable */ + if (p_cb->sec_level == SMP_SEC_AUTHENTICATED) { + link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256; + } else { + link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256; + } + } else if (btm_cb.security_mode == BTM_SEC_MODE_SP) { + /* BR/EDR transport is SSP capable */ + if (p_cb->sec_level == SMP_SEC_AUTHENTICATED) { + link_key_type = BTM_LKEY_TYPE_AUTH_COMB; + } else { + link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB; + } + } else { + SMP_TRACE_ERROR ("%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x", + __func__, btm_cb.security_mode, p_dev_rec->sm4); + return FALSE; + } + + link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET; + + UINT8 *p; + BT_OCTET16 notif_link_key; + p = notif_link_key; + ARRAY16_TO_STREAM(p, link_key); + + btm_sec_link_key_notification (bda_for_lk, notif_link_key, link_key_type); + + SMP_TRACE_EVENT ("%s is completed", __func__); + } + + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_long_term_key_from_link_key +** +** Description The function calculates and saves SC LTK derived from BR/EDR +** link key. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +*******************************************************************************/ +BOOLEAN smp_calculate_long_term_key_from_link_key(tSMP_CB *p_cb) +{ + BOOLEAN ret = TRUE; + tBTM_SEC_DEV_REC *p_dev_rec; + UINT8 rev_link_key[16]; + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); + + if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL) { + SMP_TRACE_ERROR("%s failed to find Security Record", __FUNCTION__); + return FALSE; + } + + UINT8 br_link_key_type; + if ((br_link_key_type = BTM_SecGetDeviceLinkKeyType (p_cb->pairing_bda)) + == BTM_LKEY_TYPE_IGNORE) { + SMP_TRACE_ERROR("%s failed to retrieve BR link type", __FUNCTION__); + return FALSE; + } + + if ((br_link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256) && + (br_link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) { + SMP_TRACE_ERROR("%s LE SC LTK can't be derived from LK %d", + __FUNCTION__, br_link_key_type); + return FALSE; + } + + UINT8 *p1; + UINT8 *p2; + p1 = rev_link_key; + p2 = p_dev_rec->link_key; + REVERSE_ARRAY_TO_STREAM(p1, p2, 16); + + BT_OCTET16 intermediate_long_term_key; + /* "tmp2" obtained from the spec */ + ret = smp_calculate_h6(rev_link_key, (UINT8 *) "2pmt" /* reversed "tmp2" */, + intermediate_long_term_key); + + if (!ret) { + SMP_TRACE_ERROR("%s failed to derive intermediate_long_term_key", __FUNCTION__); + return ret; + } + + /* "brle" obtained from the spec */ + ret = smp_calculate_h6(intermediate_long_term_key, (UINT8 *) "elrb" /* reversed "brle" */, + p_cb->ltk); + + if (!ret) { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + } else { + p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) + ? SMP_SEC_AUTHENTICATED : SMP_SEC_UNAUTHENTICATE; + SMP_TRACE_EVENT ("%s is completed", __FUNCTION__); + } + + return ret; +} + +/******************************************************************************* +** +** Function smp_calculate_h6 +** +** Description The function calculates +** C = h6(W, KeyID) = AES-CMAC (KeyID) +** W +** where +** input: W is 128 bit, +** KeyId is 32 bit, +** output: C is 128 bit. +** +** Returns FALSE if out of resources, TRUE in other cases. +** +** Note The LSB is the first octet, the MSB is the last octet of +** the AES-CMAC input/output stream. +** +*******************************************************************************/ +BOOLEAN smp_calculate_h6(UINT8 *w, UINT8 *keyid, UINT8 *c) +{ +#if SMP_DEBUG == TRUE + UINT8 *p_print = NULL; +#endif + + SMP_TRACE_DEBUG ("%s", __FUNCTION__); +#if SMP_DEBUG == TRUE + p_print = w; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"W", BT_OCTET16_LEN); + p_print = keyid; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"keyID", 4); +#endif + + UINT8 *p = NULL; + UINT8 key[BT_OCTET16_LEN]; + + p = key; + ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN); + +#if SMP_DEBUG == TRUE + p_print = key; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"K", BT_OCTET16_LEN); +#endif + + UINT8 msg_len = 4 /* KeyID size */; + UINT8 msg[4]; + + p = msg; + ARRAY_TO_STREAM(p, keyid, 4); + +#if SMP_DEBUG == TRUE + p_print = msg; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *) "M", msg_len); +#endif + + BOOLEAN ret = TRUE; + UINT8 cmac[BT_OCTET16_LEN]; + if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) { + SMP_TRACE_ERROR("%s failed", __FUNCTION__); + ret = FALSE; + } + +#if SMP_DEBUG == TRUE + p_print = cmac; + smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN); +#endif + + p = c; + ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN); + return ret; +} + +/******************************************************************************* +** +** Function smp_start_nonce_generation +** +** Description This function starts nonce generation. +** +** Returns void +** +*******************************************************************************/ +void smp_start_nonce_generation(tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s", __FUNCTION__); + p_cb->rand_enc_proc_state = SMP_GEN_NONCE_0_7; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** +** Function smp_finish_nonce_generation +** +** Description This function finishes nonce generation. +** +** Returns void +** +*******************************************************************************/ +void smp_finish_nonce_generation(tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s", __FUNCTION__); + p_cb->rand_enc_proc_state = SMP_GEN_NONCE_8_15; + if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) { + smp_rand_back(NULL); + } +} + +/******************************************************************************* +** +** Function smp_process_new_nonce +** +** Description This function notifies SM that it has new nonce. +** +** Returns void +** +*******************************************************************************/ +void smp_process_new_nonce(tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG ("%s round %d", __FUNCTION__, p_cb->round); + smp_sm_event(p_cb, SMP_HAVE_LOC_NONCE_EVT, NULL); +} + +/******************************************************************************* +** +** Function smp_rand_back +** +** Description This function is to process the rand command finished, +** process the random/encrypted number for further action. +** +** Returns void +** +*******************************************************************************/ +static void smp_rand_back(tBTM_RAND_ENC *p) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 *pp = p->param_buf; + UINT8 failure = SMP_PAIR_FAIL_UNKNOWN; + UINT8 state = p_cb->rand_enc_proc_state & ~0x80; + + SMP_TRACE_DEBUG ("%s state=0x%x", __FUNCTION__, state); + if (p && p->status == HCI_SUCCESS) { + switch (state) { + case SMP_GEN_SRAND_MRAND: + memcpy((void *)p_cb->rand, p->param_buf, p->param_len); + smp_generate_rand_cont(p_cb, NULL); + break; + + case SMP_GEN_SRAND_MRAND_CONT: + memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len); + smp_generate_confirm(p_cb, NULL); + break; + + case SMP_GEN_DIV_LTK: + STREAM_TO_UINT16(p_cb->div, pp); + smp_generate_ltk_cont(p_cb, NULL); + break; + + case SMP_GEN_DIV_CSRK: + STREAM_TO_UINT16(p_cb->div, pp); + smp_compute_csrk(p_cb, NULL); + break; + + case SMP_GEN_TK: + smp_proc_passkey(p_cb, p); + break; + + case SMP_GEN_RAND_V: + memcpy(p_cb->enc_rand, p->param_buf, BT_OCTET8_LEN); + smp_generate_y(p_cb, NULL); + break; + + case SMP_GENERATE_PRIVATE_KEY_0_7: + case SMP_GENERATE_PRIVATE_KEY_8_15: + case SMP_GENERATE_PRIVATE_KEY_16_23: + case SMP_GENERATE_PRIVATE_KEY_24_31: + smp_continue_private_key_creation(p_cb, p); + break; + + case SMP_GEN_NONCE_0_7: + memcpy((void *)p_cb->rand, p->param_buf, p->param_len); + smp_finish_nonce_generation(p_cb); + break; + + case SMP_GEN_NONCE_8_15: + memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len); + smp_process_new_nonce(p_cb); + break; + } + + return; + } + + SMP_TRACE_ERROR("%s key generation failed: (%d)", __FUNCTION__, p_cb->rand_enc_proc_state); + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); +} + +#endif diff --git a/lib/bt/host/bluedroid/stack/smp/smp_l2c.c b/lib/bt/host/bluedroid/stack/smp/smp_l2c.c new file mode 100644 index 00000000..a6f06705 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/smp_l2c.c @@ -0,0 +1,344 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains functions for the SMP L2Cap interface + * + ******************************************************************************/ + +#include "common/bt_target.h" +#include "osi/allocator.h" + +#if SMP_INCLUDED == TRUE + +#include <string.h> +#include "stack/btm_ble_api.h" +#include "stack/l2c_api.h" + +#include "smp_int.h" + + +static void smp_tx_complete_callback(UINT16 cid, UINT16 num_pkt); +#if (BLE_INCLUDED == TRUE) + +static void smp_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, + tBT_TRANSPORT transport); +static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf); +#endif ///BLE_INCLUDED == TRUE +#if (CLASSIC_BT_INCLUDED == TRUE) +static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, + tBT_TRANSPORT transport); +static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf); +#endif ///CLASSIC_BT_INCLUDED == TRUE + +/******************************************************************************* +** +** Function smp_l2cap_if_init +** +** Description This function is called during the SMP task startup +** to register interface functions with L2CAP. +** +*******************************************************************************/ +void smp_l2cap_if_init (void) +{ + tL2CAP_FIXED_CHNL_REG fixed_reg; + SMP_TRACE_EVENT ("SMDBG l2c %s", __func__); + fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE; + fixed_reg.fixed_chnl_opts.max_transmit = 0; + fixed_reg.fixed_chnl_opts.rtrans_tout = 0; + fixed_reg.fixed_chnl_opts.mon_tout = 0; + fixed_reg.fixed_chnl_opts.mps = 0; + fixed_reg.fixed_chnl_opts.tx_win_sz = 0; + + fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback; + + fixed_reg.pL2CA_FixedCong_Cb = NULL; /* do not handle congestion on this channel */ + fixed_reg.default_idle_tout = 0; /* set 0 seconds timeout, 0xffff default idle timeout. + This timeout is used to wait for the end of the pairing + and then make a disconnect request, setting a larger value + will cause the disconnect event to go back up for a long time. + Set to 0 will be disconnected directly, and it will come up + pairing failure, so it will not cause adverse effects. */ +#if (BLE_INCLUDED == TRUE) + fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback; + fixed_reg.pL2CA_FixedData_Cb = smp_data_received; + L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg); +#endif ///BLE_INCLUDED == TRUE + +#if (CLASSIC_BT_INCLUDED == TRUE) + fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback; + fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received; + + L2CA_RegisterFixedChannel (L2CAP_SMP_BR_CID, &fixed_reg); +#endif ///CLASSIC_BT_INCLUDED == TRUE +} + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function smp_connect_callback +** +** Description This callback function is called by L2CAP to indicate that +** SMP channel is +** connected (conn = TRUE)/disconnected (conn = FALSE). +** +*******************************************************************************/ +static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, + tBT_TRANSPORT transport) +{ + tSMP_CB *p_cb = &smp_cb; + tSMP_INT_DATA int_data; + BD_ADDR dummy_bda = {0}; + + SMP_TRACE_EVENT ("SMDBG l2c %s\n", __FUNCTION__); + + if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0) { + return; + } + if(!connected) { + //free timer + btu_free_timer(&p_cb->rsp_timer_ent); + } + if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) { + SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s\n", + __FUNCTION__, + (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3], + (bd_addr[4] << 8) + bd_addr[5], + (connected) ? "connected" : "disconnected"); + + if (connected) { + if (!p_cb->connect_initialized) { + p_cb->connect_initialized = TRUE; + /* initiating connection established */ + p_cb->role = L2CA_GetBleConnRole(bd_addr); + + /* initialize local i/r key to be default keys */ + p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY; + p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ; + p_cb->cb_evt = SMP_IO_CAP_REQ_EVT; + smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL); + } + } else { + int_data.reason = reason; + /* Disconnected while doing security */ + smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data); + } + } +} + +/******************************************************************************* +** +** Function smp_data_received +** +** Description This function is called when data is received from L2CAP on +** SMP channel. +** +** +** Returns void +** +*******************************************************************************/ +static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 cmd ; + SMP_TRACE_EVENT ("\nSMDBG l2c %s\n", __FUNCTION__); + + STREAM_TO_UINT8(cmd, p); + + /* sanity check */ + if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { + SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x\n", cmd); + osi_free (p_buf); + return; + } + + /* reject the pairing request if there is an on-going SMP pairing */ + if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) { + if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE) && + !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) { + p_cb->role = L2CA_GetBleConnRole(bd_addr); + memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN); + } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) { + osi_free (p_buf); + smp_reject_unexpected_pairing_command(bd_addr); + return; + } + /* else, out of state pairing request/security request received, passed into SM */ + } + + if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) { + btu_stop_timer (&p_cb->rsp_timer_ent); + btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, + SMP_WAIT_FOR_RSP_TOUT); + + if (cmd == SMP_OPCODE_CONFIRM) { + SMP_TRACE_DEBUG ("in %s cmd = 0x%02x, peer_auth_req = 0x%02x," + "loc_auth_req = 0x%02x\n", + __FUNCTION__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req); + + if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && + (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) { + cmd = SMP_OPCODE_PAIR_COMMITM; + } + } + + p_cb->rcvd_cmd_code = cmd; + p_cb->rcvd_cmd_len = (UINT8) p_buf->len; + smp_sm_event(p_cb, cmd, p); + } + + osi_free (p_buf); +} +#endif ///BLE_INCLUDED == TRUE + +/******************************************************************************* +** +** Function smp_tx_complete_callback +** +** Description SMP channel tx complete callback +** +*******************************************************************************/ +static void smp_tx_complete_callback (UINT16 cid, UINT16 num_pkt) +{ + tSMP_CB *p_cb = &smp_cb; + + if (p_cb->total_tx_unacked >= num_pkt) { + p_cb->total_tx_unacked -= num_pkt; + } else { + SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__, num_pkt); + } + + UINT8 reason = SMP_SUCCESS; + if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) { + if (cid == L2CAP_SMP_CID) { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason); + } else { +#if (CLASSIC_BT_INCLUDED == TRUE) + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); +#endif ///CLASSIC_BT_INCLUDED == TRUE + } + } +} + +/******************************************************************************* +** +** Function smp_br_connect_callback +** +** Description This callback function is called by L2CAP to indicate that +** SMP BR channel is +** connected (conn = TRUE)/disconnected (conn = FALSE). +** +*******************************************************************************/ +#if (CLASSIC_BT_INCLUDED == TRUE) +static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, + UINT16 reason, tBT_TRANSPORT transport) +{ + tSMP_CB *p_cb = &smp_cb; + tSMP_INT_DATA int_data; + + SMP_TRACE_EVENT ("%s", __func__); + + if (transport != BT_TRANSPORT_BR_EDR) { + SMP_TRACE_EVENT ("%s is called on unexpected transport %d\n", + __func__, transport); + return; + } + + if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)) { + return; + } + + SMP_TRACE_EVENT ("%s for pairing BDA: %08x%04x Event: %s\n", + __func__, + (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3], + (bd_addr[4] << 8) + bd_addr[5], + (connected) ? "connected" : "disconnected"); + + if (connected) { + if (!p_cb->connect_initialized) { + p_cb->connect_initialized = TRUE; + /* initialize local i/r key to be default keys */ + p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY; + p_cb->loc_auth_req = p_cb->peer_auth_req = 0; + p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT; + smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL); + } + } else { + int_data.reason = reason; + /* Disconnected while doing security */ + smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data); + } +} + +/******************************************************************************* +** +** Function smp_br_data_received +** +** Description This function is called when data is received from L2CAP on +** SMP BR channel. +** +** Returns void +** +*******************************************************************************/ +static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 cmd ; + SMP_TRACE_EVENT ("SMDBG l2c %s\n", __func__); + + STREAM_TO_UINT8(cmd, p); + + /* sanity check */ + if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { + SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd); + osi_free(p_buf); + return; + } + + /* reject the pairing request if there is an on-going SMP pairing */ + if (SMP_OPCODE_PAIRING_REQ == cmd) { + if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) { + p_cb->role = HCI_ROLE_SLAVE; + p_cb->smp_over_br = TRUE; + memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN); + } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) { + osi_free (p_buf); + smp_reject_unexpected_pairing_command(bd_addr); + return; + } + /* else, out of state pairing request received, passed into State Machine */ + } + + if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) { + btu_stop_timer (&p_cb->rsp_timer_ent); + btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, + SMP_WAIT_FOR_RSP_TOUT); + + p_cb->rcvd_cmd_code = cmd; + p_cb->rcvd_cmd_len = (UINT8) p_buf->len; + smp_br_state_machine_event(p_cb, cmd, p); + } + + osi_free (p_buf); +} +#endif /* CLASSIC_BT_INCLUDED == TRUE */ + +#endif /* SMP_INCLUDED == TRUE */ diff --git a/lib/bt/host/bluedroid/stack/smp/smp_main.c b/lib/bt/host/bluedroid/stack/smp/smp_main.c new file mode 100644 index 00000000..512aca0a --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/smp_main.c @@ -0,0 +1,810 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "common/bt_target.h" + +#if SMP_INCLUDED == TRUE + +#include <string.h> +#include "smp_int.h" + +const char *const smp_state_name [] = { + "SMP_STATE_IDLE", + "SMP_STATE_WAIT_APP_RSP", + "SMP_STATE_SEC_REQ_PENDING", + "SMP_STATE_PAIR_REQ_RSP", + "SMP_STATE_WAIT_CONFIRM", + "SMP_STATE_CONFIRM", + "SMP_STATE_RAND", + "SMP_STATE_PUBLIC_KEY_EXCH", + "SMP_STATE_SEC_CONN_PHS1_START", + "SMP_STATE_WAIT_COMMITMENT", + "SMP_STATE_WAIT_NONCE", + "SMP_STATE_SEC_CONN_PHS2_START", + "SMP_STATE_WAIT_DHK_CHECK", + "SMP_STATE_DHK_CHECK", + "SMP_STATE_ENCRYPTION_PENDING", + "SMP_STATE_BOND_PENDING", + "SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA", + "SMP_STATE_MAX" +}; + +const char *const smp_event_name [] = { + "PAIRING_REQ_EVT", + "PAIRING_RSP_EVT", + "CONFIRM_EVT", + "RAND_EVT", + "PAIRING_FAILED_EVT", + "ENC_INFO_EVT", + "MASTER_ID_EVT", + "ID_INFO_EVT", + "ID_ADDR_EVT", + "SIGN_INFO_EVT", + "SECURITY_REQ_EVT", + "PAIR_PUBLIC_KEY_EVT", + "PAIR_DHKEY_CHECK_EVT", + "PAIR_KEYPRESS_NOTIFICATION_EVT", + "PAIR_COMMITMENT_EVT", + "KEY_READY_EVT", + "ENCRYPTED_EVT", + "L2CAP_CONN_EVT", + "L2CAP_DISCONN_EVT", + "API_IO_RSP_EVT", + "API_SEC_GRANT_EVT", + "TK_REQ_EVT", + "AUTH_CMPL_EVT", + "ENC_REQ_EVT", + "BOND_REQ_EVT", + "DISCARD_SEC_REQ_EVT", + "PUBLIC_KEY_EXCHANGE_REQ_EVT", + "LOCAL_PUBLIC_KEY_CRTD_EVT", + "BOTH_PUBLIC_KEYS_RCVD_EVT", + "SEC_CONN_DHKEY_COMPLETE_EVT", + "HAVE_LOCAL_NONCE_EVT", + "SEC_CONN_PHASE1_CMPLT_EVT", + "SEC_CONN_CALC_NC_EVT", + "SEC_CONN_DISPLAY_NC_EVT", + "SEC_CONN_OK_EVT", + "SEC_CONN_2_DHCK_CHECKS_PRESENT_EVT", + "SEC_CONN_KEY_READY_EVT", + "KEYPRESS_NOTIFICATION_EVT", + "SEC_CONN_OOB_DATA_EVT", + "CREATE_LOCAL_SEC_CONN_OOB_DATA_EVT", + "OUT_OF_RANGE_EVT" +}; + +const char *smp_get_event_name(tSMP_EVENT event); +const char *smp_get_state_name(tSMP_STATE state); + +#define SMP_SM_IGNORE 0 +#define SMP_NUM_ACTIONS 2 +#define SMP_SME_NEXT_STATE 2 +#define SMP_SM_NUM_COLS 3 + +typedef const UINT8(*tSMP_SM_TBL)[SMP_SM_NUM_COLS]; + +enum { + SMP_PROC_SEC_REQ, + SMP_SEND_PAIR_REQ, + SMP_SEND_PAIR_RSP, + SMP_SEND_CONFIRM, + SMP_SEND_PAIR_FAIL, + SMP_SEND_RAND, + SMP_SEND_ENC_INFO, + SMP_SEND_ID_INFO, + SMP_SEND_LTK_REPLY, + SMP_PROC_PAIR_CMD, + SMP_PROC_PAIR_FAIL, + SMP_PROC_CONFIRM, + SMP_PROC_RAND, + SMP_PROC_ENC_INFO, + SMP_PROC_MASTER_ID, + SMP_PROC_ID_INFO, + SMP_PROC_ID_ADDR, + SMP_PROC_SRK_INFO, + SMP_PROC_SEC_GRANT, + SMP_PROC_SL_KEY, + SMP_PROC_COMPARE, + SMP_PROC_IO_RSP, + SMP_GENERATE_COMPARE, + SMP_GENERATE_CONFIRM, + SMP_GENERATE_STK, + SMP_KEY_DISTRIBUTE, + SMP_START_ENC, + SMP_PAIRING_CMPL, + SMP_DECIDE_ASSO_MODEL, + SMP_SEND_APP_CBACK, + SMP_CHECK_AUTH_REQ, + SMP_PAIR_TERMINATE, + SMP_ENC_CMPL, + SMP_PROC_DISCARD, + SMP_CREATE_PRIVATE_KEY, + SMP_USE_OOB_PRIVATE_KEY, + SMP_SEND_PAIR_PUBLIC_KEY, + SMP_PROCESS_PAIR_PUBLIC_KEY, + SMP_HAVE_BOTH_PUBLIC_KEYS, + SMP_START_SEC_CONN_PHASE1, + SMP_PROCESS_LOCAL_NONCE, + SMP_SEND_COMMITMENT, + SMP_PROCESS_PAIRING_COMMITMENT, + SMP_PROCESS_PEER_NONCE, + SMP_CALCULATE_LOCAL_DHKEY_CHECK, + SMP_SEND_DHKEY_CHECK, + SMP_PROCESS_DHKEY_CHECK, + SMP_CALCULATE_PEER_DHKEY_CHECK, + SMP_MATCH_DHKEY_CHECKS, + SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, + SMP_MOVE_TO_SEC_CONN_PHASE2, + SMP_PH2_DHKEY_CHECKS_ARE_PRESENT, + SMP_WAIT_FOR_BOTH_PUBLIC_KEYS, + SMP_START_PASSKEY_VERIFICATION, + SMP_SEND_KEYPRESS_NOTIFICATION, + SMP_PROCESS_KEYPRESS_NOTIFICATION, + SMP_PROCESS_SECURE_CONNECTION_OOB_DATA, + SMP_SET_LOCAL_OOB_KEYS, + SMP_SET_LOCAL_OOB_RAND_COMMITMENT, + SMP_IDLE_TERMINATE, + SMP_FAST_CONN_PARAM, + SMP_SM_NO_ACTION +}; + +#if (BLE_INCLUDED == TRUE) +static const tSMP_ACT smp_sm_action[SMP_SM_NO_ACTION] = { + smp_proc_sec_req, + smp_send_pair_req, + smp_send_pair_rsp, + smp_send_confirm, + smp_send_pair_fail, + smp_send_rand, + smp_send_enc_info, + smp_send_id_info, + smp_send_ltk_reply, + smp_proc_pair_cmd, + smp_proc_pair_fail, + smp_proc_confirm, + smp_proc_rand, + smp_proc_enc_info, + smp_proc_master_id, + smp_proc_id_info, + smp_proc_id_addr, + smp_proc_srk_info, + smp_proc_sec_grant, + smp_proc_sl_key, + smp_proc_compare, + smp_process_io_response, + smp_generate_compare, + smp_generate_srand_mrand_confirm, + smp_generate_stk, + smp_key_distribution, + smp_start_enc, + smp_pairing_cmpl, + smp_decide_association_model, + smp_send_app_cback, + smp_check_auth_req, + smp_pair_terminate, + smp_enc_cmpl, + smp_proc_discard, + smp_create_private_key, + smp_use_oob_private_key, + smp_send_pair_public_key, + smp_process_pairing_public_key, + smp_both_have_public_keys, + smp_start_secure_connection_phase1, + smp_process_local_nonce, + smp_send_commitment, + smp_process_pairing_commitment, + smp_process_peer_nonce, + smp_calculate_local_dhkey_check, + smp_send_dhkey_check, + smp_process_dhkey_check, + smp_calculate_peer_dhkey_check, + smp_match_dhkey_checks, + smp_calculate_numeric_comparison_display_number, + smp_move_to_secure_connections_phase2, + smp_phase_2_dhkey_checks_are_present, + smp_wait_for_both_public_keys, + smp_start_passkey_verification, + smp_send_keypress_notification, + smp_process_keypress_notification, + smp_process_secure_connection_oob_data, + smp_set_local_oob_keys, + smp_set_local_oob_random_commitment, + smp_idle_terminate, + smp_fast_conn_param +}; +#else +static const tSMP_ACT smp_sm_action[SMP_SM_NO_ACTION] = {NULL}; +#endif ///BLE_INCLUDED == TRUE + +/************ SMP Master FSM State/Event Indirection Table **************/ +static const UINT8 smp_master_entry_map[][SMP_STATE_MAX] = { + /* state name: Idle WaitApp SecReq Pair Wait Confirm Rand PublKey SCPhs1 Wait Wait SCPhs2 Wait DHKChk Enc Bond CrLocSc + Rsp Pend ReqRsp Cfm Exch Strt Cmtm Nonce Strt DHKChk Pend Pend OobData */ + /* PAIR_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* PAIR_RSP */{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* CONFIRM */{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* RAND */{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + /* PAIR_FAIL */{ 0, 0x81, 0, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0, 0x81, 0 }, + /* ENC_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + /* MASTER_ID */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 }, + /* ID_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 }, + /* ID_ADDR */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 }, + /* SIGN_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 }, + /* SEC_REQ */{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* PAIR_PUBLIC_KEY */{ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* PAIR_DHKEY_CHCK */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, + /* PAIR_KEYPR_NOTIF */{ 0, 8, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0 }, + /* PAIR_COMMITM */{ 0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0 }, + /* KEY_READY */{ 0, 3, 0, 3, 1, 0, 2, 0, 4, 0, 0, 0, 0, 0, 1, 6, 0 }, + /* ENC_CMPL */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 }, + /* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* L2C_DISC */{ 3, 0x83, 0, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0 }, + /* IO_RSP */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SEC_GRANT */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* AUTH_CMPL */{ 4, 0x82, 0, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0 }, + /* ENC_REQ */{ 0, 4, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 }, + /* BOND_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, + /* DISCARD_SEC_REQ */{ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, + /* PUBL_KEY_EXCH_REQ */{ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* LOC_PUBL_KEY_CRTD */{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + /* BOTH_PUBL_KEYS_RCVD */{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SC_DHKEY_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* HAVE_LOC_NONCE */{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2 }, + /* SC_PHASE1_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, + /* SC_CALC_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, + /* SC_DSPL_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 }, + /* SC_NC_OK */{ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SC_2_DHCK_CHKS_PRES */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SC_KEY_READY */{ 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + /* KEYPR_NOTIF */{ 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SC_OOB_DATA */{ 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* CR_LOC_SC_OOB_DATA */{ 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +static const UINT8 smp_all_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* PAIR_FAIL */ {SMP_PROC_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_STATE_IDLE}, + /* AUTH_CMPL */ {SMP_SEND_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_STATE_IDLE}, + /* L2C_DISC */ {SMP_PAIR_TERMINATE, SMP_SM_NO_ACTION, SMP_STATE_IDLE} +}; + +static const UINT8 smp_master_idle_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* SEC_REQ */ {SMP_PROC_SEC_REQ, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, + /* L2C_DISC */ {SMP_IDLE_TERMINATE, SMP_SM_NO_ACTION, SMP_STATE_IDLE}, + /* AUTH_CMPL */ {SMP_PAIRING_CMPL, SMP_SM_NO_ACTION, SMP_STATE_IDLE} + /* CR_LOC_SC_OOB_DATA */ , {SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA} + +}; + +static const UINT8 smp_master_wait_for_app_response_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* SEC_GRANT */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, + /* IO_RSP */ {SMP_SEND_PAIR_REQ, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP}, + + /* TK ready */ + /* KEY_READY */ {SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM}, + + /* start enc mode setup */ + /* ENC_REQ */ { SMP_START_ENC, SMP_FAST_CONN_PARAM, SMP_STATE_ENCRYPTION_PENDING}, + /* DISCARD_SEC_REQ */ { SMP_PROC_DISCARD, SMP_SM_NO_ACTION, SMP_STATE_IDLE} + /* user confirms NC 'OK', i.e. phase 1 is completed */ + /* SC_NC_OK */, { SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START}, + /* user-provided passkey is rcvd */ + /* SC_KEY_READY */ { SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, + /* PAIR_KEYPR_NOTIF */ { SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, + /* KEYPR_NOTIF */ { SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* SC_OOB_DATA */ { SMP_USE_OOB_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH} +}; + +static const UINT8 smp_master_pair_request_response_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* PAIR_RSP */ { SMP_PROC_PAIR_CMD, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, + /* TK_REQ */ { SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + + /* TK ready */ + /* KEY_READY */{ SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM} + /* PUBL_KEY_EXCH_REQ */, { SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH} +}; + +static const UINT8 smp_master_wait_for_confirm_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* KEY_READY*/ {SMP_SEND_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}/* CONFIRM ready */ +}; + +static const UINT8 smp_master_confirm_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* CONFIRM */ { SMP_PROC_CONFIRM, SMP_SEND_RAND, SMP_STATE_RAND} +}; + +static const UINT8 smp_master_rand_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* RAND */ { SMP_PROC_RAND, SMP_GENERATE_COMPARE, SMP_STATE_RAND}, + /* KEY_READY*/ { SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_STATE_RAND}, /* Compare ready */ + /* ENC_REQ */ { SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING} +}; + +static const UINT8 smp_master_public_key_exchange_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* LOC_PUBL_KEY_CRTD */{ SMP_SEND_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, + /* PAIR_PUBLIC_KEY */{ SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, + /* BOTH_PUBL_KEYS_RCVD */{ SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +}; + +static const UINT8 smp_master_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* SC_DHKEY_CMPLT */{ SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, + /* HAVE_LOC_NONCE */{ SMP_PROCESS_LOCAL_NONCE, SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT}, + /* TK_REQ */{ SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display,*/ + /* It's time to start commitment calculation */ + /* KEY_READY */{ SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, + /* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_SEC_CONN_PHS1_START}, + /* PAIR_COMMITM */{ SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +}; + +static const UINT8 smp_master_wait_commitment_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* PAIR_COMMITM */{ SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_RAND, SMP_STATE_WAIT_NONCE}, + /* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_COMMITMENT}, +}; + +static const UINT8 smp_master_wait_nonce_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* peer nonce is received */ + /* RAND */{SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START}, + /* NC model, time to calculate number for NC */ + /* SC_CALC_NC */{SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION, SMP_STATE_WAIT_NONCE}, + /* NC model, time to display calculated number for NC to the user */ + /* SC_DSPL_NC */{SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +}; + +static const UINT8 smp_master_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* SC_PHASE1_CMPLT */{SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_SEND_DHKEY_CHECK, SMP_STATE_WAIT_DHK_CHECK}, +}; + +static const UINT8 smp_master_wait_dhk_check_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_STATE_DHK_CHECK}, +}; + +static const UINT8 smp_master_dhk_check_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* locally calculated peer dhkey check is ready -> compare it withs DHKey Check actually received from peer */ + /* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, + /* locally calculated peer dhkey check is ready -> calculate STK, go to sending */ + /* HCI LE Start Encryption command */ + /* ENC_REQ */{SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, +}; + +static const UINT8 smp_master_enc_pending_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* STK ready */ + /* KEY_READY */ { SMP_START_ENC, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, + /* ENCRYPTED */ { SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, + /* BOND_REQ */ { SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} +}; +static const UINT8 smp_master_bond_pending_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* SIGN_INFO*/ { SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* KEY_READY */{SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} /* LTK ready */ +}; + +static const UINT8 smp_master_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* LOC_PUBL_KEY_CRTD */ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}, + /* HAVE_LOC_NONCE */ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE} +}; + + +/************ SMP Slave FSM State/Event Indirection Table **************/ +static const UINT8 smp_slave_entry_map[][SMP_STATE_MAX] = { + /* state name: Idle WaitApp SecReq Pair Wait Confirm Rand PublKey SCPhs1 Wait Wait SCPhs2 Wait DHKChk Enc Bond CrLocSc + Rsp Pend ReqRsp Cfm Exch Strt Cmtm Nonce Strt DHKChk Pend Pend OobData */ + /* PAIR_REQ */{ 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* PAIR_RSP */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* CONFIRM */{ 0, 4, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* RAND */{ 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + /* PAIR_FAIL */{ 0, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0, 0 }, + /* ENC_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 }, + /* MASTER_ID */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 }, + /* ID_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 }, + /* ID_ADDR */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 }, + /* SIGN_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 }, + /* SEC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* PAIR_PUBLIC_KEY */{ 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* PAIR_DHKEY_CHCK */{ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0 }, + /* PAIR_KEYPR_NOTIF */{ 0, 9, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0 }, + /* PAIR_COMMITM */{ 0, 8, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0 }, + /* KEY_READY */{ 0, 3, 0, 3, 2, 2, 1, 0, 4, 0, 0, 0, 0, 0, 2, 1, 0 }, + /* ENC_CMPL */{ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 }, + /* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* L2C_DISC */{ 0, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0 }, + /* IO_RSP */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SEC_GRANT */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* AUTH_CMPL */{ 0, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0 }, + /* ENC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, + /* BOND_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0 }, + /* DISCARD_SEC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* PUBL_KEY_EXCH_REQ */{ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* LOC_PUBL_KEY_CRTD */{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + /* BOTH_PUBL_KEYS_RCVD */{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SC_DHKEY_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* HAVE_LOC_NONCE */{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2 }, + /* SC_PHASE1_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, + /* SC_CALC_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, + /* SC_DSPL_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 }, + /* SC_NC_OK */{ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SC_2_DHCK_CHKS_PRES */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0 }, + /* SC_KEY_READY */{ 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + /* KEYPR_NOTIF */{ 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* SC_OOB_DATA */{ 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* CR_LOC_SC_OOB_DATA */{ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +static const UINT8 smp_slave_idle_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* PAIR_REQ */ {SMP_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP} + /* CR_LOC_SC_OOB_DATA */ , {SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA} +}; + +static const UINT8 smp_slave_wait_for_app_response_table [][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* IO_RSP */ {SMP_PROC_IO_RSP, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP}, + /* SEC_GRANT */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, + + /* TK ready */ + /* KEY_READY */ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM} + /* DHKey Check from master is received before phase 1 is completed - race */ + /* PAIR_DHKEY_CHCK */, {SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* user confirms NC 'OK', i.e. phase 1 is completed */ + /* SC_NC_OK */ {SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START}, + /* user-provided passkey is rcvd */ + /* SC_KEY_READY */ {SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, + /* PAIR_COMMITM */ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* PAIR_KEYPR_NOTIF */ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}, + /* KEYPR_NOTIF */ {SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* SC_OOB_DATA */ {SMP_SEND_PAIR_RSP, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, +}; + +static const UINT8 smp_slave_sec_request_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* PAIR_REQ */{SMP_PROC_PAIR_CMD, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, + /* ENCRYPTED*/{SMP_ENC_CMPL, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, +}; + +static const UINT8 smp_slave_pair_request_response_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}, + /* TK_REQ */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* TK/Confirm ready */ + /* KEY_READY */{SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP} + /* PUBL_KEY_EXCH_REQ */, { SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, + /* PAIR_PUBLIC_KEY */ { SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}, +}; + +static const UINT8 smp_slave_wait_confirm_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SEND_CONFIRM, SMP_STATE_CONFIRM}, + /* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM} +}; + +static const UINT8 smp_slave_confirm_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* RAND */ {SMP_PROC_RAND, SMP_GENERATE_COMPARE, SMP_STATE_RAND}, + + /* TK/Confirm ready */ + /* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM} +}; + +static const UINT8 smp_slave_rand_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* KEY_READY */ {SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_STATE_RAND}, /* compare match */ + /* RAND */ {SMP_SEND_RAND, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING} +}; + +static const UINT8 smp_slave_public_key_exch_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* LOC_PUBL_KEY_CRTD */{ SMP_WAIT_FOR_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, + /* PAIR_PUBLIC_KEY */{ SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}, + /* BOTH_PUBL_KEYS_RCVD */{ SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +}; + +static const UINT8 smp_slave_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* SC_DHKEY_CMPLT */{ SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, + /* HAVE_LOC_NONCE */{ SMP_PROCESS_LOCAL_NONCE, SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT}, + /* TK_REQ */{ SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, + /* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display, it's time to start */ + /* commitment calculation */ + /* KEY_READY */{ SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, + /* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_SEC_CONN_PHS1_START}, + /*COMMIT*/{SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START}, +}; + +static const UINT8 smp_slave_wait_commitment_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* PAIR_COMMITM */{SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_COMMITMENT, SMP_STATE_WAIT_NONCE}, + /* PAIR_KEYPR_NOTIF */{SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_COMMITMENT}, +}; + +static const UINT8 smp_slave_wait_nonce_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* peer nonce is received */ + /* RAND */{SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START}, + /* NC model, time to calculate number for NC */ + /* SC_CALC_NC */{SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION, SMP_STATE_WAIT_NONCE}, + /* NC model, time to display calculated number for NC to the user */ + /* SC_DSPL_NC */{SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP}, +}; + +static const UINT8 smp_slave_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* SC_PHASE1_CMPLT */{SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_PH2_DHKEY_CHECKS_ARE_PRESENT, SMP_STATE_WAIT_DHK_CHECK}, + /* DHKey Check from master is received before slave DHKey calculation is completed - race */ + /* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START}, +}; + +static const UINT8 smp_slave_wait_dhk_check_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_STATE_DHK_CHECK}, + /* DHKey Check from master was received before slave came to this state */ + /* SC_2_DHCK_CHKS_PRES */{SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, +}; + +static const UINT8 smp_slave_dhk_check_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + + /* locally calculated peer dhkey check is ready -> compare it withs DHKey Check */ + /* actually received from peer */ + /* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, + + /* dhkey checks match -> send local dhkey check to master, go to wait for HCI LE */ + /* Long Term Key Request Event */ + /* PAIR_DHKEY_CHCK */{SMP_SEND_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, +}; + +static const UINT8 smp_slave_enc_pending_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* ENC_REQ */ {SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, + + /* STK ready */ + /* KEY_READY */ {SMP_SEND_LTK_REPLY, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, + /* ENCRYPTED */ {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}, + /* BOND_REQ */ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} +}; +static const UINT8 smp_slave_bond_pending_table[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + + /* LTK ready */ + /* KEY_READY */{ SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + + /* rev SRK */ + /* SIGN_INFO */{ SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}, + /* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} + +}; + +static const UINT8 smp_slave_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = { + /* Event Action Next State */ + /* LOC_PUBL_KEY_CRTD */ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}, + /* HAVE_LOC_NONCE */ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE} +}; + +static const tSMP_SM_TBL smp_state_table[][2] = { + /* SMP_STATE_IDLE */ + {smp_master_idle_table, smp_slave_idle_table}, + + /* SMP_STATE_WAIT_APP_RSP */ + {smp_master_wait_for_app_response_table, smp_slave_wait_for_app_response_table}, + + /* SMP_STATE_SEC_REQ_PENDING */ + {NULL, smp_slave_sec_request_table}, + + /* SMP_STATE_PAIR_REQ_RSP */ + {smp_master_pair_request_response_table, smp_slave_pair_request_response_table}, + + /* SMP_STATE_WAIT_CONFIRM */ + {smp_master_wait_for_confirm_table, smp_slave_wait_confirm_table}, + + /* SMP_STATE_CONFIRM */ + {smp_master_confirm_table, smp_slave_confirm_table}, + + /* SMP_STATE_RAND */ + {smp_master_rand_table, smp_slave_rand_table}, + + /* SMP_STATE_PUBLIC_KEY_EXCH */ + {smp_master_public_key_exchange_table, smp_slave_public_key_exch_table}, + + /* SMP_STATE_SEC_CONN_PHS1_START */ + {smp_master_sec_conn_phs1_start_table, smp_slave_sec_conn_phs1_start_table}, + + /* SMP_STATE_WAIT_COMMITMENT */ + {smp_master_wait_commitment_table, smp_slave_wait_commitment_table}, + + /* SMP_STATE_WAIT_NONCE */ + {smp_master_wait_nonce_table, smp_slave_wait_nonce_table}, + + /* SMP_STATE_SEC_CONN_PHS2_START */ + {smp_master_sec_conn_phs2_start_table, smp_slave_sec_conn_phs2_start_table}, + + /* SMP_STATE_WAIT_DHK_CHECK */ + {smp_master_wait_dhk_check_table, smp_slave_wait_dhk_check_table}, + + /* SMP_STATE_DHK_CHECK */ + {smp_master_dhk_check_table, smp_slave_dhk_check_table}, + + /* SMP_STATE_ENCRYPTION_PENDING */ + {smp_master_enc_pending_table, smp_slave_enc_pending_table}, + + /* SMP_STATE_BOND_PENDING */ + {smp_master_bond_pending_table, smp_slave_bond_pending_table}, + + /* SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA */ + {smp_master_create_local_sec_conn_oob_data, smp_slave_create_local_sec_conn_oob_data} +}; + +typedef const UINT8 (*tSMP_ENTRY_TBL)[SMP_STATE_MAX]; +static const tSMP_ENTRY_TBL smp_entry_table[] = { + smp_master_entry_map, + smp_slave_entry_map +}; + +#if SMP_DYNAMIC_MEMORY == FALSE +tSMP_CB smp_cb; +#else +tSMP_CB *smp_cb_ptr; +#endif +#define SMP_ALL_TBL_MASK 0x80 + +/******************************************************************************* +** Function smp_set_state +** Returns None +*******************************************************************************/ +void smp_set_state(tSMP_STATE state) +{ + if (state < SMP_STATE_MAX) { + SMP_TRACE_DEBUG( "State change: %s(%d) ==> %s(%d)", + smp_get_state_name(smp_cb.state), smp_cb.state, + smp_get_state_name(state), state ); + smp_cb.state = state; + } else { + SMP_TRACE_DEBUG("smp_set_state invalid state =%d", state ); + } +} + +/******************************************************************************* +** Function smp_get_state +** Returns The smp state +*******************************************************************************/ +tSMP_STATE smp_get_state(void) +{ + return smp_cb.state; +} + +/******************************************************************************* +** +** Function smp_sm_event +** +** Description Handle events to the state machine. It looks up the entry +** in the smp_entry_table array. +** If it is a valid entry, it gets the state table.Set the next state, +** if not NULL state.Execute the action function according to the +** state table. If the state returned by action function is not NULL +** state, adjust the new state to the returned state.If (api_evt != MAX), +** call callback function. +** +** Returns void. +** +*******************************************************************************/ +void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data) +{ + UINT8 curr_state = p_cb->state; + tSMP_SM_TBL state_table; + UINT8 action, entry, i; + tSMP_ENTRY_TBL entry_table = smp_entry_table[p_cb->role]; + + SMP_TRACE_EVENT("main smp_sm_event\n"); + if (curr_state >= SMP_STATE_MAX) { + SMP_TRACE_DEBUG( "Invalid state: %d\n", curr_state) ; + return; + } + + SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]", \ + (p_cb->role == 0x01) ? "Slave" : "Master\n", smp_get_state_name( p_cb->state), + p_cb->state, smp_get_event_name(event), event) ; + + /* look up the state table for the current state */ + /* lookup entry /w event & curr_state */ + /* If entry is ignore, return. + * Otherwise, get state table (according to curr_state or all_state) */ + if ((event <= SMP_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state]) != SMP_SM_IGNORE )) { + if (entry & SMP_ALL_TBL_MASK) { + entry &= ~SMP_ALL_TBL_MASK; + state_table = smp_all_table; + } else { + state_table = smp_state_table[curr_state][p_cb->role ? 1 : 0]; + } + } else { + SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]\n", + smp_get_event_name(event), event, smp_get_state_name(curr_state), + curr_state); + return; + } + + /* Get possible next state from state table. */ + + smp_set_state(state_table[entry - 1][SMP_SME_NEXT_STATE]); + + /* If action is not ignore, clear param, exec action and get next state. + * The action function may set the Param for cback. + * Depending on param, call cback or free buffer. */ + /* execute action */ + /* execute action functions */ + for (i = 0; i < SMP_NUM_ACTIONS; i++) { + if ((action = state_table[entry - 1][i]) != SMP_SM_NO_ACTION && smp_sm_action[action] != NULL) { + (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data); + } else { + break; + } + } + SMP_TRACE_DEBUG( "result state = %s\n", smp_get_state_name( p_cb->state ) ) ; +} + +/******************************************************************************* +** Function smp_get_state_name +** Returns The smp state name. +*******************************************************************************/ +const char *smp_get_state_name(tSMP_STATE state) +{ + const char *p_str = smp_state_name[SMP_STATE_MAX]; + + if (state < SMP_STATE_MAX) { + p_str = smp_state_name[state]; + } + return p_str; +} + +/******************************************************************************* +** Function smp_get_event_name +** Returns The smp event name. +*******************************************************************************/ +const char *smp_get_event_name(tSMP_EVENT event) +{ + const char *p_str = smp_event_name[SMP_MAX_EVT]; + + if (event <= SMP_MAX_EVT) { + p_str = smp_event_name[event - 1]; + } + return p_str; +} + +#endif diff --git a/lib/bt/host/bluedroid/stack/smp/smp_utils.c b/lib/bt/host/bluedroid/stack/smp/smp_utils.c new file mode 100644 index 00000000..2e9fac77 --- /dev/null +++ b/lib/bt/host/bluedroid/stack/smp/smp_utils.c @@ -0,0 +1,1645 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +******************************************************************************/ + +/****************************************************************************** + * + * This file contains functions for the SMP L2CAP utility functions + * + ******************************************************************************/ +#include "common/bt_target.h" + +#if SMP_INCLUDED == TRUE + +#include "stack/bt_types.h" +//#include "bt_utils.h" +#include <string.h> +//#include <ctype.h> +#include "stack/hcidefs.h" +#include "stack/btm_ble_api.h" +#include "stack/l2c_api.h" +#include "l2c_int.h" +#include "smp_int.h" +#include "device/controller.h" +#include "btm_int.h" +#include "common/bte_appl.h" + +#define SMP_PAIRING_REQ_SIZE 7 +#define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1) +#define SMP_RAND_CMD_SIZE (BT_OCTET16_LEN + 1) +#define SMP_INIT_CMD_SIZE (BT_OCTET16_LEN + 1) +#define SMP_ENC_INFO_SIZE (BT_OCTET16_LEN + 1) +#define SMP_MASTER_ID_SIZE (BT_OCTET8_LEN + 2 + 1) +#define SMP_ID_INFO_SIZE (BT_OCTET16_LEN + 1) +#define SMP_ID_ADDR_SIZE (BD_ADDR_LEN + 1 + 1) +#define SMP_SIGN_INFO_SIZE (BT_OCTET16_LEN + 1) +#define SMP_PAIR_FAIL_SIZE 2 +#define SMP_SECURITY_REQUEST_SIZE 2 +#define SMP_PAIR_PUBL_KEY_SIZE (1 /* opcode */ + (2*BT_OCTET32_LEN)) +#define SMP_PAIR_COMMITM_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*Commitment*/) +#define SMP_PAIR_DHKEY_CHECK_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*DHKey Check*/) +#define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/) + +/* SMP command sizes per spec */ +static const UINT8 smp_cmd_size_per_spec[] = { + 0, + SMP_PAIRING_REQ_SIZE, /* 0x01: pairing request */ + SMP_PAIRING_REQ_SIZE, /* 0x02: pairing response */ + SMP_CONFIRM_CMD_SIZE, /* 0x03: pairing confirm */ + SMP_RAND_CMD_SIZE, /* 0x04: pairing random */ + SMP_PAIR_FAIL_SIZE, /* 0x05: pairing failed */ + SMP_ENC_INFO_SIZE, /* 0x06: encryption information */ + SMP_MASTER_ID_SIZE, /* 0x07: master identification */ + SMP_ID_INFO_SIZE, /* 0x08: identity information */ + SMP_ID_ADDR_SIZE, /* 0x09: identity address information */ + SMP_SIGN_INFO_SIZE, /* 0x0A: signing information */ + SMP_SECURITY_REQUEST_SIZE, /* 0x0B: security request */ + SMP_PAIR_PUBL_KEY_SIZE, /* 0x0C: pairing public key */ + SMP_PAIR_DHKEY_CHECK_SIZE, /* 0x0D: pairing dhkey check */ + SMP_PAIR_KEYPR_NOTIF_SIZE, /* 0x0E: pairing keypress notification */ + SMP_PAIR_COMMITM_SIZE /* 0x0F: pairing commitment */ +}; + +static BOOLEAN smp_parameter_unconditionally_valid(tSMP_CB *p_cb); +static BOOLEAN smp_parameter_unconditionally_invalid(tSMP_CB *p_cb); + +/* type for SMP command length validation functions */ +typedef BOOLEAN (*tSMP_CMD_LEN_VALID)(tSMP_CB *p_cb); + +static BOOLEAN smp_command_has_valid_fixed_length(tSMP_CB *p_cb); + +static const tSMP_CMD_LEN_VALID smp_cmd_len_is_valid[] = { + smp_parameter_unconditionally_invalid, + smp_command_has_valid_fixed_length, /* 0x01: pairing request */ + smp_command_has_valid_fixed_length, /* 0x02: pairing response */ + smp_command_has_valid_fixed_length, /* 0x03: pairing confirm */ + smp_command_has_valid_fixed_length, /* 0x04: pairing random */ + smp_command_has_valid_fixed_length, /* 0x05: pairing failed */ + smp_command_has_valid_fixed_length, /* 0x06: encryption information */ + smp_command_has_valid_fixed_length, /* 0x07: master identification */ + smp_command_has_valid_fixed_length, /* 0x08: identity information */ + smp_command_has_valid_fixed_length, /* 0x09: identity address information */ + smp_command_has_valid_fixed_length, /* 0x0A: signing information */ + smp_command_has_valid_fixed_length, /* 0x0B: security request */ + smp_command_has_valid_fixed_length, /* 0x0C: pairing public key */ + smp_command_has_valid_fixed_length, /* 0x0D: pairing dhkey check */ + smp_command_has_valid_fixed_length, /* 0x0E: pairing keypress notification */ + smp_command_has_valid_fixed_length /* 0x0F: pairing commitment */ +}; + +/* type for SMP command parameter ranges validation functions */ +typedef BOOLEAN (*tSMP_CMD_PARAM_RANGES_VALID)(tSMP_CB *p_cb); + +static BOOLEAN smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb); +static BOOLEAN smp_pairing_keypress_notification_is_valid(tSMP_CB *p_cb); + +static const tSMP_CMD_PARAM_RANGES_VALID smp_cmd_param_ranges_are_valid[] = { + smp_parameter_unconditionally_invalid, + smp_pairing_request_response_parameters_are_valid, /* 0x01: pairing request */ + smp_pairing_request_response_parameters_are_valid, /* 0x02: pairing response */ + smp_parameter_unconditionally_valid, /* 0x03: pairing confirm */ + smp_parameter_unconditionally_valid, /* 0x04: pairing random */ + smp_parameter_unconditionally_valid, /* 0x05: pairing failed */ + smp_parameter_unconditionally_valid, /* 0x06: encryption information */ + smp_parameter_unconditionally_valid, /* 0x07: master identification */ + smp_parameter_unconditionally_valid, /* 0x08: identity information */ + smp_parameter_unconditionally_valid, /* 0x09: identity address information */ + smp_parameter_unconditionally_valid, /* 0x0A: signing information */ + smp_parameter_unconditionally_valid, /* 0x0B: security request */ + smp_parameter_unconditionally_valid, /* 0x0C: pairing public key */ + smp_parameter_unconditionally_valid, /* 0x0D: pairing dhkey check */ + smp_pairing_keypress_notification_is_valid, /* 0x0E: pairing keypress notification */ + smp_parameter_unconditionally_valid /* 0x0F: pairing commitment */ +}; + +/* type for action functions */ +typedef BT_HDR *(*tSMP_CMD_ACT)(UINT8 cmd_code, tSMP_CB *p_cb); + +static BT_HDR *smp_build_pairing_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_confirm_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pairing_fail(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_encrypt_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_security_request(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pair_public_key_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pairing_commitment_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pair_dhkey_check_cmd(UINT8 cmd_code, tSMP_CB *p_cb); +static BT_HDR *smp_build_pairing_keypress_notification_cmd(UINT8 cmd_code, tSMP_CB *p_cb); + +static const tSMP_CMD_ACT smp_cmd_build_act[] = { + NULL, + smp_build_pairing_cmd, /* 0x01: pairing request */ + smp_build_pairing_cmd, /* 0x02: pairing response */ + smp_build_confirm_cmd, /* 0x03: pairing confirm */ + smp_build_rand_cmd, /* 0x04: pairing random */ + smp_build_pairing_fail, /* 0x05: pairing failure */ + smp_build_encrypt_info_cmd, /* 0x06: encryption information */ + smp_build_master_id_cmd, /* 0x07: master identification */ + smp_build_identity_info_cmd, /* 0x08: identity information */ + smp_build_id_addr_cmd, /* 0x09: identity address information */ + smp_build_signing_info_cmd, /* 0x0A: signing information */ + smp_build_security_request, /* 0x0B: security request */ + smp_build_pair_public_key_cmd, /* 0x0C: pairing public key */ + smp_build_pair_dhkey_check_cmd, /* 0x0D: pairing DHKey check */ + smp_build_pairing_keypress_notification_cmd, /* 0x0E: pairing keypress notification */ + smp_build_pairing_commitment_cmd /* 0x0F: pairing commitment */ +}; + +static const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = { + /* display only */ /* Display Yes/No */ /* keyboard only */ + /* No Input/Output */ /* keyboard display */ + + /* initiator */ + /* model = tbl[peer_io_caps][loc_io_caps] */ + /* Display Only */ + { { + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY + }, + + /* Display Yes/No */ + { + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY + }, + + /* Keyboard only */ + { + SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF + }, + + /* No Input No Output */ + { + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY + }, + + /* keyboard display */ + { + SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF + } + }, + + /* responder */ + /* model = tbl[loc_io_caps][peer_io_caps] */ + /* Display Only */ + { { + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF + }, + + /* Display Yes/No */ + { + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF + }, + + /* keyboard only */ + { + SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY + }, + + /* No Input No Output */ + { + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY + }, + + /* keyboard display */ + { + SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, + SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY + } + } +}; + +static const UINT8 smp_association_table_sc[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = { + /* display only */ /* Display Yes/No */ /* keyboard only */ + /* No InputOutput */ /* keyboard display */ + + /* initiator */ + /* model = tbl[peer_io_caps][loc_io_caps] */ + + /* Display Only */ + { { + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT + }, + + /* Display Yes/No */ + { + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP + }, + + /* keyboard only */ + { + SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP + }, + + /* No Input No Output */ + { + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS + }, + + /* keyboard display */ + { + SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP + } + }, + + /* responder */ + /* model = tbl[loc_io_caps][peer_io_caps] */ + + /* Display Only */ + { { + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP + }, + + /* Display Yes/No */ + { + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_DISP, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP + }, + + /* keyboard only */ + { + SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT + }, + + /* No Input No Output */ + { + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS + }, + + /* keyboard display */ + { + SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_DISP, + SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP + } + } +}; + +static tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB *p_cb); +static tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB *p_cb); + +/******************************************************************************* +** +** Function smp_send_msg_to_L2CAP +** +** Description Send message to L2CAP. +** +*******************************************************************************/ +BOOLEAN smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP) +{ + UINT16 l2cap_ret; + UINT16 fixed_cid = L2CAP_SMP_CID; + + if (smp_cb.smp_over_br) { + fixed_cid = L2CAP_SMP_BR_CID; + } + + SMP_TRACE_EVENT("%s", __FUNCTION__); + smp_cb.total_tx_unacked += 1; + + if ((l2cap_ret = L2CA_SendFixedChnlData (fixed_cid, rem_bda, p_toL2CAP)) == L2CAP_DW_FAILED) { + smp_cb.total_tx_unacked -= 1; + SMP_TRACE_ERROR("SMP failed to pass msg:0x%0x to L2CAP", + *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset)); + return FALSE; + } else { + return TRUE; + } +} + +/******************************************************************************* +** +** Function smp_send_cmd +** +** Description send a SMP command on L2CAP channel. +** +*******************************************************************************/ +BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf; + BOOLEAN sent = FALSE; + UINT8 failure = SMP_PAIR_INTERNAL_ERR; + SMP_TRACE_EVENT("smp_send_cmd on l2cap cmd_code=0x%x\n", cmd_code); + if ( cmd_code <= (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */) && + smp_cmd_build_act[cmd_code] != NULL) { + p_buf = (*smp_cmd_build_act[cmd_code])(cmd_code, p_cb); + + if (p_buf != NULL && + smp_send_msg_to_L2CAP(p_cb->pairing_bda, p_buf)) { + sent = TRUE; + + btu_stop_timer (&p_cb->rsp_timer_ent); + btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD, + SMP_WAIT_FOR_RSP_TOUT); + } + } + + if (!sent) { + if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure); +#endif ///CLASSIC_BT_INCLUDED == TRUE + } else { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + } + } + return sent; +} + +/******************************************************************************* +** +** Function smp_rsp_timeout +** +** Description Called when SMP wait for SMP command response timer expires +** +** Returns void +** +*******************************************************************************/ +void smp_rsp_timeout(TIMER_LIST_ENT *p_tle) +{ + tSMP_CB *p_cb = &smp_cb; + UINT8 failure = SMP_RSP_TIMEOUT; + UNUSED(p_tle); + + SMP_TRACE_EVENT("%s state:%d br_state:%d", __FUNCTION__, p_cb->state, p_cb->br_state); + + if (p_cb->smp_over_br) { +#if (CLASSIC_BT_INCLUDED == TRUE) + smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure); +#endif ///CLASSIC_BT_INCLUDED == TRUE + } else { + smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure); + } +} + +/******************************************************************************* +** +** Function smp_build_pairing_req_cmd +** +** Description Build pairing request command. +** +*******************************************************************************/ +BT_HDR *smp_build_pairing_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + + SMP_TRACE_EVENT("smp_build_pairing_cmd"); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_PAIRING_REQ_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, cmd_code); + UINT8_TO_STREAM (p, p_cb->local_io_capability); + UINT8_TO_STREAM (p, p_cb->loc_oob_flag); + UINT8_TO_STREAM (p, p_cb->loc_auth_req); + UINT8_TO_STREAM (p, p_cb->loc_enc_size); + UINT8_TO_STREAM (p, p_cb->local_i_key); + UINT8_TO_STREAM (p, p_cb->local_r_key); + + p_buf->offset = L2CAP_MIN_OFFSET; + /* 1B ERR_RSP op code + 1B cmd_op_code + 2B handle + 1B status */ + p_buf->len = SMP_PAIRING_REQ_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_confirm_cmd +** +** Description Build confirm request command. +** +*******************************************************************************/ +static BT_HDR *smp_build_confirm_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("smp_build_confirm_cmd\n"); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_CONFIRM_CMD_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_CONFIRM); + ARRAY_TO_STREAM (p, p_cb->confirm, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_CONFIRM_CMD_SIZE; + } + + return p_buf; +} +/******************************************************************************* +** +** Function smp_build_rand_cmd +** +** Description Build Random command. +** +*******************************************************************************/ +static BT_HDR *smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s\n", __func__); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_RAND_CMD_SIZE + L2CAP_MIN_OFFSET)) + != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_RAND); + ARRAY_TO_STREAM (p, p_cb->rand, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_RAND_CMD_SIZE; + } + + return p_buf; +} +/******************************************************************************* +** +** Function smp_build_encrypt_info_cmd +** +** Description Build security information command. +** +*******************************************************************************/ +static BT_HDR *smp_build_encrypt_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("smp_build_encrypt_info_cmd\n"); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_ENC_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_ENCRYPT_INFO); + ARRAY_TO_STREAM (p, p_cb->ltk, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_ENC_INFO_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_master_id_cmd +** +** Description Build security information command. +** +*******************************************************************************/ +static BT_HDR *smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s\n", __func__); + + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_MASTER_ID_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_MASTER_ID); + UINT16_TO_STREAM (p, p_cb->ediv); + ARRAY_TO_STREAM (p, p_cb->enc_rand, BT_OCTET8_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_MASTER_ID_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_identity_info_cmd +** +** Description Build identity information command. +** +*******************************************************************************/ +static BT_HDR *smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; +#if (BLE_INCLUDED == TRUE) + UINT8 *p; + BT_OCTET16 irk; + UNUSED(cmd_code); + UNUSED(p_cb); + + SMP_TRACE_EVENT("smp_build_identity_info_cmd\n"); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + BTM_GetDeviceIDRoot(irk); + + UINT8_TO_STREAM (p, SMP_OPCODE_IDENTITY_INFO); + ARRAY_TO_STREAM (p, irk, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_ID_INFO_SIZE; + } + +#endif ///BLE_INCLUDED == TRUE + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_id_addr_cmd +** +** Description Build identity address information command. +** +*******************************************************************************/ +static BT_HDR *smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + + UNUSED(cmd_code); + UNUSED(p_cb); + SMP_TRACE_EVENT("smp_build_id_addr_cmd\n"); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_ID_ADDR); + /* Identity Address Information is used in the Transport Specific Key Distribution phase to distribute + its public device address or static random address. if slave using static random address is encrypted, + it should distribute its static random address */ +#if (BLE_INCLUDED == TRUE) + if(btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM && memcmp(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr,6) == 0) { + UINT8_TO_STREAM (p, 0x01); + BDADDR_TO_STREAM (p, btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr); + } else +#endif ///BLE_INCLUDED == TRUE + { + UINT8_TO_STREAM (p, 0); + BDADDR_TO_STREAM (p, controller_get_interface()->get_address()->address); + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_ID_ADDR_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_signing_info_cmd +** +** Description Build signing information command. +** +*******************************************************************************/ +static BT_HDR *smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("smp_build_signing_info_cmd\n"); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_SIGN_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_SIGN_INFO); + ARRAY_TO_STREAM (p, p_cb->csrk, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_SIGN_INFO_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_pairing_fail +** +** Description Build Pairing Fail command. +** +*******************************************************************************/ +static BT_HDR *smp_build_pairing_fail(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s\n", __func__); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIRING_FAILED); + UINT8_TO_STREAM (p, p_cb->failure); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_FAIL_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_security_request +** +** Description Build security request command. +** +*******************************************************************************/ +static BT_HDR *smp_build_security_request(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s\n", __func__); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 2 + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_SEC_REQ); + UINT8_TO_STREAM (p, p_cb->loc_auth_req); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_SECURITY_REQUEST_SIZE; + + SMP_TRACE_EVENT("opcode=%d auth_req=0x%x", SMP_OPCODE_SEC_REQ, p_cb->loc_auth_req ); + } + + return p_buf; + +} + +/******************************************************************************* +** +** Function smp_build_pair_public_key_cmd +** +** Description Build pairing public key command. +** +*******************************************************************************/ +static BT_HDR *smp_build_pair_public_key_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UINT8 publ_key[2 * BT_OCTET32_LEN]; + UINT8 *p_publ_key = publ_key; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s\n", __FUNCTION__); + + memcpy(p_publ_key, p_cb->loc_publ_key.x, BT_OCTET32_LEN); + memcpy(p_publ_key + BT_OCTET32_LEN, p_cb->loc_publ_key.y, BT_OCTET32_LEN); + + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + + SMP_PAIR_PUBL_KEY_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_PUBLIC_KEY); + ARRAY_TO_STREAM (p, p_publ_key, 2 * BT_OCTET32_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_PUBL_KEY_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_pairing_commitment_cmd +** +** Description Build pairing commitment command. +** +*******************************************************************************/ +static BT_HDR *smp_build_pairing_commitment_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s\n", __func__); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_COMMITM_SIZE + L2CAP_MIN_OFFSET)) + != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_CONFIRM); + ARRAY_TO_STREAM (p, p_cb->commitment, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_COMMITM_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_pair_dhkey_check_cmd +** +** Description Build pairing DHKey check command. +** +*******************************************************************************/ +static BT_HDR *smp_build_pair_dhkey_check_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s\n", __FUNCTION__); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + + SMP_PAIR_DHKEY_CHECK_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_DHKEY_CHECK); + ARRAY_TO_STREAM (p, p_cb->dhkey_check, BT_OCTET16_LEN); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_DHKEY_CHECK_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_build_pairing_keypress_notification_cmd +** +** Description Build keypress notification command. +** +*******************************************************************************/ +static BT_HDR *smp_build_pairing_keypress_notification_cmd(UINT8 cmd_code, tSMP_CB *p_cb) +{ + BT_HDR *p_buf = NULL ; + UINT8 *p; + UNUSED(cmd_code); + + SMP_TRACE_EVENT("%s\n", __FUNCTION__); + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR)\ + + SMP_PAIR_KEYPR_NOTIF_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_KEYPR_NOTIF); + UINT8_TO_STREAM (p, p_cb->local_keypress_notification); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_KEYPR_NOTIF_SIZE; + } + + return p_buf; +} + +/******************************************************************************* +** +** Function smp_convert_string_to_tk +** +** Description This function is called to convert a 6 to 16 digits numeric +** character string into SMP TK. +** +** +** Returns void +** +*******************************************************************************/ +void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey) +{ + UINT8 *p = tk; + tSMP_KEY key; + SMP_TRACE_EVENT("smp_convert_string_to_tk\n"); + UINT32_TO_STREAM(p, passkey); + + key.key_type = SMP_KEY_TYPE_TK; + key.p_data = tk; + + smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key); +} + +/******************************************************************************* +** +** Function smp_mask_enc_key +** +** Description This function is called to mask off the encryption key based +** on the maximum encryption key size. +** +** +** Returns void +** +*******************************************************************************/ +void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 *p_data) +{ + SMP_TRACE_EVENT("smp_mask_enc_key\n"); + if (loc_enc_size < BT_OCTET16_LEN) { + for (; loc_enc_size < BT_OCTET16_LEN; loc_enc_size ++) { + * (p_data + loc_enc_size) = 0; + } + } + return; +} + +/******************************************************************************* +** +** Function smp_xor_128 +** +** Description utility function to do an biteise exclusive-OR of two bit +** strings of the length of BT_OCTET16_LEN. +** +** Returns void +** +*******************************************************************************/ +void smp_xor_128(BT_OCTET16 a, const BT_OCTET16 b) +{ + UINT8 i, *aa = a; + const UINT8 *bb = b; + + SMP_TRACE_EVENT("smp_xor_128\n"); + for (i = 0; i < BT_OCTET16_LEN; i++) { + aa[i] = aa[i] ^ bb[i]; + } +} + +/******************************************************************************* +** +** Function smp_cb_cleanup +** +** Description Clean up SMP control block +** +** Returns void +** +*******************************************************************************/ +void smp_cb_cleanup(tSMP_CB *p_cb) +{ + tSMP_CALLBACK *p_callback = p_cb->p_callback; + UINT8 trace_level = p_cb->trace_level; + UINT32 static_passkey = p_cb->static_passkey; + BOOLEAN use_static_passkey = p_cb->use_static_passkey; + SMP_TRACE_EVENT("smp_cb_cleanup\n"); + + memset(p_cb, 0, sizeof(tSMP_CB)); + p_cb->p_callback = p_callback; + p_cb->trace_level = trace_level; + if(use_static_passkey) { + p_cb->use_static_passkey = use_static_passkey; + p_cb->static_passkey = static_passkey; + } +} + +/******************************************************************************* +** +** Function smp_remove_fixed_channel +** +** Description This function is called to remove the fixed channel +** +** Returns void +** +*******************************************************************************/ +void smp_remove_fixed_channel(tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->smp_over_br) { + L2CA_RemoveFixedChnl (L2CAP_SMP_BR_CID, p_cb->pairing_bda); + } else { + L2CA_RemoveFixedChnl (L2CAP_SMP_CID, p_cb->pairing_bda); + } +} + +/******************************************************************************* +** +** Function smp_reset_control_value +** +** Description This function is called to reset the control block value when +** pairing procedure finished. +** +** +** Returns void +** +*******************************************************************************/ +void smp_reset_control_value(tSMP_CB *p_cb) +{ + SMP_TRACE_EVENT("smp_reset_control_value\n"); + btu_stop_timer (&p_cb->rsp_timer_ent); + p_cb->flags = 0; + /* set the link idle timer to drop the link when pairing is done + usually service discovery will follow authentication complete, to avoid + racing condition for a link down/up, set link idle timer to be + SMP_LINK_TOUT_MIN to guarantee SMP key exchange */ + L2CA_SetIdleTimeoutByBdAddr(p_cb->pairing_bda, SMP_LINK_TOUT_MIN, BT_TRANSPORT_LE); + + /* We can tell L2CAP to remove the fixed channel (if it has one) */ + smp_remove_fixed_channel(p_cb); + smp_cb_cleanup(p_cb); +} + +/******************************************************************************* +** +** Function smp_proc_pairing_cmpl +** +** Description This function is called to process pairing complete +** +** +** Returns void +** +*******************************************************************************/ +void smp_proc_pairing_cmpl(tSMP_CB *p_cb) +{ + tSMP_EVT_DATA evt_data = {0}; + tSMP_CALLBACK *p_callback = p_cb->p_callback; + BD_ADDR pairing_bda; + + SMP_TRACE_DEBUG ("smp_proc_pairing_cmpl \n"); + + evt_data.cmplt.reason = p_cb->status; + evt_data.cmplt.smp_over_br = p_cb->smp_over_br; + evt_data.cmplt.auth_mode = 0; +#if (BLE_INCLUDED == TRUE) + tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda); + if (p_cb->status == SMP_SUCCESS) { + evt_data.cmplt.sec_level = p_cb->sec_level; + if (p_cb->auth_mode) { // the first encryption + evt_data.cmplt.auth_mode = p_cb->auth_mode; + if (p_rec) { + p_rec->ble.auth_mode = p_cb->auth_mode; + } + } else if (p_rec) { + evt_data.cmplt.auth_mode = p_rec->ble.auth_mode; + } + } +#else + if (p_cb->status == SMP_SUCCESS) { + evt_data.cmplt.sec_level = p_cb->sec_level; + evt_data.cmplt.auth_mode = p_cb->auth_mode; + } +#endif + + evt_data.cmplt.is_pair_cancel = FALSE; + + if (p_cb->is_pair_cancel) { + evt_data.cmplt.is_pair_cancel = TRUE; + } + + + SMP_TRACE_DEBUG ("send SMP_COMPLT_EVT reason=0x%0x sec_level=0x%0x\n", + evt_data.cmplt.reason, + evt_data.cmplt.sec_level ); + + memcpy (pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN); + +#if (BLE_INCLUDED == TRUE) +#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE) + if (p_cb->role == HCI_ROLE_SLAVE) { + if(p_rec && p_rec->ble.skip_update_conn_param) { + //clear flag + p_rec->ble.skip_update_conn_param = false; + } else { + #if (BT_MULTI_CONNECTION_ENBALE == FALSE) + L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, TRUE); + #endif + } + } + +#endif +#endif ///BLE_INCLUDED == TRUE + + smp_reset_control_value(p_cb); + // TODO: clear local oob data when start advertising + smp_clear_local_oob_data(); + + if (p_callback) { + (*p_callback) (SMP_COMPLT_EVT, pairing_bda, &evt_data); + } +} + +/******************************************************************************* +** +** Function smp_command_has_invalid_parameters +** +** Description Checks if the received SMP command has invalid parameters i.e. +** if the command length is valid and the command parameters are +** inside specified range. +** It returns TRUE if the command has invalid parameters. +** +** Returns TRUE if the command has invalid parameters, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN smp_command_has_invalid_parameters(tSMP_CB *p_cb) +{ + UINT8 cmd_code = p_cb->rcvd_cmd_code; + + SMP_TRACE_DEBUG("%s for cmd code 0x%02x\n", __func__, cmd_code); + + if ((cmd_code > (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */)) || + (cmd_code < SMP_OPCODE_MIN)) { + SMP_TRACE_WARNING("Somehow received command with the RESERVED code 0x%02x\n", cmd_code); + return TRUE; + } + + if (!(*smp_cmd_len_is_valid[cmd_code])(p_cb)) { + return TRUE; + } + + if (!(*smp_cmd_param_ranges_are_valid[cmd_code])(p_cb)) { + return TRUE; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function smp_command_has_valid_fixed_length +** +** Description Checks if the received command size is equal to the size +** according to specs. +** +** Returns TRUE if the command size is as expected, FALSE otherwise. +** +** Note The command is expected to have fixed length. +*******************************************************************************/ +BOOLEAN smp_command_has_valid_fixed_length(tSMP_CB *p_cb) +{ + UINT8 cmd_code = p_cb->rcvd_cmd_code; + + SMP_TRACE_DEBUG("%s for cmd code 0x%02x\n", __func__, cmd_code); + + if (p_cb->rcvd_cmd_len != smp_cmd_size_per_spec[cmd_code]) { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with invalid length\ + 0x%02x (per spec the length is 0x%02x).\n", + cmd_code, p_cb->rcvd_cmd_len, smp_cmd_size_per_spec[cmd_code]); + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_pairing_request_response_parameters_are_valid +** +** Description Validates parameter ranges in the received SMP command +** pairing request or pairing response. +** The parameters to validate: +** IO capability, +** OOB data flag, +** Bonding_flags in AuthReq +** Maximum encryption key size. +** Returns FALSE if at least one of these parameters is out of range. +** +*******************************************************************************/ +BOOLEAN smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb) +{ + UINT8 io_caps = p_cb->peer_io_caps; + UINT8 oob_flag = p_cb->peer_oob_flag; + UINT8 bond_flag = p_cb->peer_auth_req & 0x03; //0x03 is gen bond with appropriate mask + UINT8 enc_size = p_cb->peer_enc_size; + + SMP_TRACE_DEBUG("%s for cmd code 0x%02x\n", __func__, p_cb->rcvd_cmd_code); + + if (io_caps >= BTM_IO_CAP_MAX) { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with IO Capabilty \ + value (0x%02x) out of range).\n", + p_cb->rcvd_cmd_code, io_caps); + return FALSE; + } + + if (!((oob_flag == SMP_OOB_NONE) || (oob_flag == SMP_OOB_PRESENT))) { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with OOB data flag value \ + (0x%02x) out of range).\n", + p_cb->rcvd_cmd_code, oob_flag); + return FALSE; + } + + if (!((bond_flag == SMP_AUTH_NO_BOND) || (bond_flag == SMP_AUTH_BOND))) { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Bonding_Flags value (0x%02x)\ + out of range).\n", + p_cb->rcvd_cmd_code, bond_flag); + return FALSE; + } + + /* `bte_appl_cfg.ble_min_enc_key_size` will be `SMP_ENCR_KEY_SIZE_MIN` by + * default if not set explicitly */ +#if (BLE_INCLUDED == TRUE) + if (enc_size < bte_appl_cfg.ble_min_key_size) { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \ + Key value (0x%02x) less than minimum required key size).\n", + p_cb->rcvd_cmd_code, enc_size); + return FALSE; + } +#else + if (enc_size < SMP_ENCR_KEY_SIZE_MIN) { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \ + Key value (0x%02x) less than minimum required key size).\n", + p_cb->rcvd_cmd_code, enc_size); + return FALSE; + } +#endif + + if (enc_size > SMP_ENCR_KEY_SIZE_MAX) { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \ + Key value (0x%02x) greater than supported by stack).\n", + p_cb->rcvd_cmd_code, enc_size); + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_pairing_keypress_notification_is_valid +** +** Description Validates Notification Type parameter range in the received SMP command +** pairing keypress notification. +** Returns FALSE if this parameter is out of range. +** +*******************************************************************************/ +BOOLEAN smp_pairing_keypress_notification_is_valid(tSMP_CB *p_cb) +{ + tBTM_SP_KEY_TYPE keypress_notification = p_cb->peer_keypress_notification; + + SMP_TRACE_DEBUG("%s for cmd code 0x%02x\n", __func__, p_cb->rcvd_cmd_code); + + if (keypress_notification >= BTM_SP_KEY_OUT_OF_RANGE) { + SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Pairing Keypress \ + Notification value (0x%02x) out of range).\n", + p_cb->rcvd_cmd_code, keypress_notification); + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function smp_parameter_unconditionally_valid +** +** Description Always returns TRUE. +** +*******************************************************************************/ +BOOLEAN smp_parameter_unconditionally_valid(tSMP_CB *p_cb) +{ + return TRUE; +} + +/******************************************************************************* +** +** Function smp_parameter_unconditionally_invalid +** +** Description Always returns FALSE. +** +*******************************************************************************/ +BOOLEAN smp_parameter_unconditionally_invalid(tSMP_CB *p_cb) +{ + return FALSE; +} + +/******************************************************************************* +** +** Function smp_reject_unexpected_pairing_command +** +** Description send pairing failure to an unexpected pairing command during +** an active pairing process. +** +** Returns void +** +*******************************************************************************/ +void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr) +{ + BT_HDR *p_buf; + UINT8 *p; + + SMP_TRACE_DEBUG ("%s\n", __FUNCTION__); + + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + \ + SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET)) != NULL) { + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + UINT8_TO_STREAM (p, SMP_OPCODE_PAIRING_FAILED); + UINT8_TO_STREAM (p, SMP_PAIR_NOT_SUPPORT); + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = SMP_PAIR_FAIL_SIZE; + + smp_send_msg_to_L2CAP(bd_addr, p_buf); + } +} + +/******************************************************************************* +** Function smp_select_association_model +** +** Description This function selects association model to use for STK +** generation. Selection is based on both sides' io capability, +** oob data flag and authentication request. +** +** Note If Secure Connections Only mode is required locally then we +** come to this point only if both sides support Secure Connections +** mode, i.e. if p_cb->secure_connections_only_mode_required = TRUE then we come +** to this point only if +** (p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) == +** (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) == +** SMP_SC_SUPPORT_BIT +** +*******************************************************************************/ +tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB *p_cb) +{ + tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; + p_cb->le_secure_connections_mode_is_used = FALSE; + + SMP_TRACE_EVENT("%s\n", __FUNCTION__); + SMP_TRACE_DEBUG("%s p_cb->peer_io_caps = %d p_cb->local_io_capability = %d\n", + __FUNCTION__, p_cb->peer_io_caps, p_cb->local_io_capability); + SMP_TRACE_DEBUG("%s p_cb->peer_oob_flag = %d p_cb->loc_oob_flag = %d\n", + __FUNCTION__, p_cb->peer_oob_flag, p_cb->loc_oob_flag); + SMP_TRACE_DEBUG("%s p_cb->peer_auth_req = 0x%02x p_cb->loc_auth_req = 0x%02x\n", + __FUNCTION__, p_cb->peer_auth_req, p_cb->loc_auth_req); + SMP_TRACE_DEBUG("%s p_cb->secure_connections_only_mode_required = %s\n", + __FUNCTION__, p_cb->secure_connections_only_mode_required ? + "TRUE" : "FALSE"); + + if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) { + p_cb->le_secure_connections_mode_is_used = TRUE; + } + + SMP_TRACE_DEBUG("use_sc_process = %d\n", p_cb->le_secure_connections_mode_is_used); + + if (p_cb->le_secure_connections_mode_is_used) { + model = smp_select_association_model_secure_connections(p_cb); + } else { + model = smp_select_legacy_association_model(p_cb); + } + return model; +} + +/******************************************************************************* +** Function smp_select_legacy_association_model +** +** Description This function is called to select association mode if at least +** one side doesn't support secure connections. +** +*******************************************************************************/ +tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB *p_cb) +{ + tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; + + SMP_TRACE_DEBUG("%s\n", __func__); + /* if OOB data is present on both devices, then use OOB association model */ + if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT) { + return SMP_MODEL_OOB; + } + + /* else if neither device requires MITM, then use Just Works association model */ + if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) && SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req)) { + return SMP_MODEL_ENCRYPTION_ONLY; + } + + /* otherwise use IO capability to select association model */ + if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->local_io_capability < SMP_IO_CAP_MAX) { + if (p_cb->role == HCI_ROLE_MASTER) { + model = smp_association_table[p_cb->role][p_cb->peer_io_caps] + [p_cb->local_io_capability]; + } else { + model = smp_association_table[p_cb->role][p_cb->local_io_capability] + [p_cb->peer_io_caps]; + } + } + + return model; +} + +/******************************************************************************* +** Function smp_select_association_model_secure_connections +** +** Description This function is called to select association mode if both +** sides support secure connections. +** +*******************************************************************************/ +tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB *p_cb) +{ + tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE; + + SMP_TRACE_DEBUG("%s\n", __func__); + /* if OOB data is present on at least one device, then use OOB association model */ + if (p_cb->peer_oob_flag == SMP_OOB_PRESENT || p_cb->loc_oob_flag == SMP_OOB_PRESENT) { + return SMP_MODEL_SEC_CONN_OOB; + } + + /* else if neither device requires MITM, then use Just Works association model */ + if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) && SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req)) { + return SMP_MODEL_SEC_CONN_JUSTWORKS; + } + + /* otherwise use IO capability to select association model */ + if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->local_io_capability < SMP_IO_CAP_MAX) { + if (p_cb->role == HCI_ROLE_MASTER) { + model = smp_association_table_sc[p_cb->role][p_cb->peer_io_caps] + [p_cb->local_io_capability]; + } else { + model = smp_association_table_sc[p_cb->role][p_cb->local_io_capability] + [p_cb->peer_io_caps]; + } + } + + return model; +} + +/******************************************************************************* +** Function smp_reverse_array +** +** Description This function reverses array bytes +** +*******************************************************************************/ +void smp_reverse_array(UINT8 *arr, UINT8 len) +{ + UINT8 i = 0, tmp; + + SMP_TRACE_DEBUG("smp_reverse_array\n"); + + for (i = 0; i < len / 2; i ++) { + tmp = arr[i]; + arr[i] = arr[len - 1 - i]; + arr[len - 1 - i] = tmp; + } +} + +/******************************************************************************* +** Function smp_calculate_random_input +** +** Description This function returns random input value to be used in commitment +** calculation for SC passkey entry association mode +** (if bit["round"] in "random" array == 1 then returns 0x81 +** else returns 0x80). +** +** Returns ri value +** +*******************************************************************************/ +UINT8 smp_calculate_random_input(UINT8 *random, UINT8 round) +{ + UINT8 i = round / 8; + UINT8 j = round % 8; + UINT8 ri; + + SMP_TRACE_DEBUG("random: 0x%02x, round: %d, i: %d, j: %d\n", random[i], round, i, j); + ri = ((random[i] >> j) & 1) | 0x80; + SMP_TRACE_DEBUG("%s ri=0x%02x\n", __func__, ri); + return ri; +} + +/******************************************************************************* +** Function smp_collect_local_io_capabilities +** +** Description This function puts into IOcap array local device +** IOCapability, OOB data, AuthReq. +** +** Returns void +** +*******************************************************************************/ +void smp_collect_local_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + iocap[0] = p_cb->local_io_capability; + iocap[1] = p_cb->loc_oob_flag; + iocap[2] = p_cb->loc_auth_req; +} + +/******************************************************************************* +** Function smp_collect_peer_io_capabilities +** +** Description This function puts into IOcap array peer device +** IOCapability, OOB data, AuthReq. +** +** Returns void +** +*******************************************************************************/ +void smp_collect_peer_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb) +{ + SMP_TRACE_DEBUG("%s\n", __func__); + + iocap[0] = p_cb->peer_io_caps; + iocap[1] = p_cb->peer_oob_flag; + iocap[2] = p_cb->peer_auth_req; +} +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** Function smp_collect_local_ble_address +** +** Description This function puts into le_addr array local device le address: +** le_addr[0-5] = local BD ADDR, +** le_addr[6] = local le address type (PUBLIC/RANDOM). +** +** Returns void +** +*******************************************************************************/ +void smp_collect_local_ble_address(UINT8 *le_addr, tSMP_CB *p_cb) +{ + tBLE_ADDR_TYPE addr_type = 0; + BD_ADDR bda; + UINT8 *p = le_addr; + + SMP_TRACE_DEBUG("%s\n", __func__); + + BTM_ReadConnectionAddr( p_cb->pairing_bda, bda, &addr_type); + BDADDR_TO_STREAM(p, bda); + UINT8_TO_STREAM(p, addr_type); +} + +/******************************************************************************* +** Function smp_collect_peer_ble_address +** +** Description This function puts into le_addr array peer device le address: +** le_addr[0-5] = peer BD ADDR, +** le_addr[6] = peer le address type (PUBLIC/RANDOM). +** +** Returns void +** +*******************************************************************************/ +void smp_collect_peer_ble_address(UINT8 *le_addr, tSMP_CB *p_cb) +{ + tBLE_ADDR_TYPE addr_type = 0; + BD_ADDR bda; + UINT8 *p = le_addr; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda, &addr_type)) { + SMP_TRACE_ERROR("can not collect peer le addr information for unknown device\n"); + return; + } + + BDADDR_TO_STREAM(p, bda); + UINT8_TO_STREAM(p, addr_type); +} + +/******************************************************************************* +** Function smp_check_commitment +** +** Description This function compares peer commitment values: +** - expected (i.e. calculated locally), +** - received from the peer. +** +** Returns TRUE if the values are the same +** FALSE otherwise +** +*******************************************************************************/ +BOOLEAN smp_check_commitment(tSMP_CB *p_cb) +{ + BT_OCTET16 expected; + + SMP_TRACE_DEBUG("%s\n", __func__); + + smp_calculate_peer_commitment(p_cb, expected); + print128(expected, (const UINT8 *)"calculated peer commitment"); + print128(p_cb->remote_commitment, (const UINT8 *)"received peer commitment"); + + if (memcmp(p_cb->remote_commitment, expected, BT_OCTET16_LEN)) { + SMP_TRACE_WARNING("Commitment check fails\n"); + return FALSE; + } + + SMP_TRACE_DEBUG("Commitment check succeeds\n"); + return TRUE; +} + +/******************************************************************************* +** +** Function smp_save_secure_connections_long_term_key +** +** Description The function saves SC LTK as BLE key for future use as local +** and/or peer key. +** +** Returns void +** +*******************************************************************************/ +void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb) +{ + tBTM_LE_LENC_KEYS lle_key; + tBTM_LE_PENC_KEYS ple_key; + + SMP_TRACE_DEBUG("%s-Save LTK as local LTK key\n", __func__); + memcpy(lle_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + lle_key.div = 0; + lle_key.key_size = p_cb->loc_enc_size; + lle_key.sec_level = p_cb->sec_level; + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, (tBTM_LE_KEY_VALUE *)&lle_key, TRUE); + + SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key\n", __func__); + ple_key.ediv = 0; + memset(ple_key.rand, 0, BT_OCTET8_LEN); + memcpy(ple_key.ltk, p_cb->ltk, BT_OCTET16_LEN); + ple_key.sec_level = p_cb->sec_level; + ple_key.key_size = p_cb->loc_enc_size; + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, (tBTM_LE_KEY_VALUE *)&ple_key, TRUE); +} + +/******************************************************************************* +** +** Function smp_calculate_f5_mackey_and_long_term_key +** +** Description The function calculates MacKey and LTK and saves them in CB. +** To calculate MacKey and LTK it calls smp_calc_f5(...). +** MacKey is used in dhkey calculation, LTK is used to encrypt +** the link. +** +** Returns FALSE if out of resources, TRUE otherwise. +** +*******************************************************************************/ +BOOLEAN smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb) +{ + UINT8 a[7]; + UINT8 b[7]; + UINT8 *p_na; + UINT8 *p_nb; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->role == HCI_ROLE_MASTER) { + smp_collect_local_ble_address(a, p_cb); + smp_collect_peer_ble_address(b, p_cb); + p_na = p_cb->rand; + p_nb = p_cb->rrand; + } else { + smp_collect_local_ble_address(b, p_cb); + smp_collect_peer_ble_address(a, p_cb); + p_na = p_cb->rrand; + p_nb = p_cb->rand; + } + + if (!smp_calculate_f5(p_cb->dhkey, p_na, p_nb, a, b, p_cb->mac_key, p_cb->ltk)) { + SMP_TRACE_ERROR("%s failed\n", __func__); + return FALSE; + } + + SMP_TRACE_EVENT ("%s is completed\n", __func__); + return TRUE; +} +#endif ///BLE_INCLUDED == TRUE +/******************************************************************************* +** +** Function smp_request_oob_data +** +** Description Requests application to provide OOB data. +** +** Returns TRUE - OOB data has to be provided by application +** FALSE - otherwise (unexpected) +** +*******************************************************************************/ +BOOLEAN smp_request_oob_data(tSMP_CB *p_cb) +{ + tSMP_OOB_DATA_TYPE req_oob_type = SMP_OOB_INVALID_TYPE; + + SMP_TRACE_DEBUG("%s\n", __func__); + + if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT) { + /* both local and peer rcvd data OOB */ + req_oob_type = SMP_OOB_BOTH; + } else if (p_cb->peer_oob_flag == SMP_OOB_PRESENT) { + /* peer rcvd OOB local data, local didn't receive OOB peer data */ + req_oob_type = SMP_OOB_LOCAL; + } else if (p_cb->loc_oob_flag == SMP_OOB_PRESENT) { + req_oob_type = SMP_OOB_PEER; + } + + SMP_TRACE_DEBUG("req_oob_type = %d\n", req_oob_type); + + if (req_oob_type == SMP_OOB_INVALID_TYPE) { + return FALSE; + } + + p_cb->req_oob_type = req_oob_type; + p_cb->cb_evt = SMP_SC_OOB_REQ_EVT; + smp_sm_event(p_cb, SMP_TK_REQ_EVT, &req_oob_type); + + return TRUE; +} + + +#endif |
