1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
72
73
74
75
76
77
84
85
86
87
88
89
90
91
92
93
94
95
96
97
103
104
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
138
139
143
144
149
150
154
155
160
161
166
167
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
241
242
243
244
245
249
250
251
252
253
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
422
423
424
425
426
427
428
433
434
435
436
439
440
441
442
443
446
449
452
455
458
461
462
465
468
471
474
477
480
483
484
487
488
491
492
493
503
504
505
509
515
516
517
523
524
525
526
532
533
534
541
542
549
550
557
558
559
560
561
562
563
564
565
566
570
571
572
579
580
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
606
607
608
609
610
611
612
613
614
615
616
625
626
627
628
629
630
631
632
633
634
635
636
637
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
704
707
711
712
713
714
715
716
717
718
719
725
726
727
728
729
730
731
732
733
734
735
740
741
744
745
746
747
748
753
754
755
756
757
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
810
811
812
813
819
820
821
822
823
824
825
826
827
828
829
836
837
838
839
846
847
848
849
850
851
852
855
856
857
858
859
860
861
862
863
872
878
879
880
881
882
887
888
889
890
891
892
895
896
897
898
899
900
901
902
907
908
909
910
911
912
913
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
967
968
969
970
971
972
973
974
975
976
977
978
990
991
992
999
1000
1001
1002
1003
1008
1009
1010
1014
1015
1016
1017
1018
1021
1022
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1070
1077
1080
1083
1086
1089
1092
1093
1094
1095
1099
1100
1101
1102
1103
1104
1105
1106
1107
1112
1113
1114
1115
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1216
1217
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1245
1246
1247
1248
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1335
1336
1340
1341
1342
1343
1345
1346
1347
1348
1349
1350
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1378
1379
1380
1381
1382
1383
1384
1385
1386
1391
1392
1393
1397
1398
1399
1400
1401
1402
1403
1404
1405
1408
1409
1413
1414
1415
1416
1420
1421
1422
1423
1424
1428
1429
1430
1431
1434
1435
1436
1438
1439
1440
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1496
1497
1498
1499
1500
1501
1505
1506
1507
1508
1509
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1529
1530
1531
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1573
1574
1575
1576
1577
1585
1586
1602
1603
1604
1605
1606
1607
1611
1612
1613
1614
1615
1616
1617
1622
1623
1624
1627
1628
1629
1630
1631
1632
1633
1634
1641
1642
1643
1653
1654
1655
1659
1662
1663
1664
1671
1674
1677
1678
1679
1680
1681
1682
1683
1684
1685
1690
1691
1692
1693
1694
1695
1696
1697
1698
1702
1710
1711
1712
1713
1714
1715
1716
1717
1721
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1748
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1777
1778
1779
1780
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1927
1928
1938
1939
1940
1941
1949
1950
1951
1957
1958
1959
1960
1969
1970
1971
1972
1973
1974
1975
1976
1981
1982
1983
1984
1985
1986
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2087
2088
2091
2092
2095
2096
2099
2100
2104
2105
2109
2110
2116
2117
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2203
2204
2205
2206
2207
2208
2228
2229
2230
2231
2232
2233
2234
2247
2248
2249
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2272
2273
2274
2275
2276
2277
2278
2283
2284
2285
2289
2290
2291
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2312
2313
2317
2318
2319
2320
2321
2322
2336
2337
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2369
2381
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2413
2414
2415
2416
2422
2423
2424
2426
2427
2428
2430
2431
2432
2433
2436
2437
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2458
2459
2463
2464
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2527
2528
2533
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2593
2594
2595
2596
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2633
2634
2642
2643
2644
2645
2646
2647
2648
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2722
2723
2724
2725
2726
2727
2737
2738
2739
2740
2741
2742
2743
2744
2745
2752
2753
2754
2763
2766
2767
2768
2769
2770
2771
2772
2775
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2838
2839
2840
2845
2846
2847
2851
2852
2853
2858
2859
2860
2861
2862
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2880
2884
2888
2892
2896
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2950
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2990
2991
2992
2993
2994
2995
2996
2997
2998
3012
3013
3014
3015
3016
3017
3018
3019
3020
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3055
3056
3057
3058
3059
3060
3061
3062
3067
3068
3069
3070
3071
3072
3073
3074
3075
3078
3079
3080
3081
3082
3083
3084
3085
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3223
3224
3225
3228
3229
3230
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3326
3327
3334
3335
3336
3337
3341
3345
3349
3353
3357
3358
3359
3360
3361
3362
3363
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3423
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3666
3667
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3715
3719
3722
3723
3724
3725
3726
3732
3733
3734
3735
3739
3740
3741
3742
3743
3744
3745
3751
3752
3753
3754
3755
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3795
3796
3797
3798
3811
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3860
3861
3862
3867
3868
3869
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3963
3964
3965
3966
3967
3973
3974
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4004
4009
4010
4011
4012
4013
4014
4015
4016
4037
4038
4039
4040
4041
4043
4044
4045
4046
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4079
4080
4081
4082
4083
4084
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4114
4115
4116
4117
4121
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4143
4144
4145
4146
4147
4164
4165
4166
4170
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4193
4194
4195
4196
4197
4198
4206
4207
4208
4209
4210
4220
4221
4222
4224
4225
4226
4228
4229
4230
4231
4232
4233
4238
4239
4240
4241
4242
4249
4250
4251
4252
4260
4261
4271
4272
4273
4274
4277
4278
4279
4280
4282
4283
4284
4286
4288
4290
4292
4293
4294
4295
4296
4297
4298
4306
4307
4308
4309
4310
4311
4312
4313
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4395
4396
4397
4398
4399
4403
4404
4405
4409
4410
4411
4412
4413
4414
4415
4416
4420
4421
4422
4423
4424
4429
4430
4434
4435
4436
4440
4441
4442
4456
4457
4458
4459
4462
4463
4464
4465
4469
4470
4471
4472
4473
4474
4478
4479
4480
4485
4486
4487
4488
4489
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4505
4506
4507
4508
4509
4510
4511
4512
4513
4517
4518
4519
4520
4521
4522
4523
4527
4528
4529
4538
4539
4540
4541
4542
4543
4547
4548
4549
4550
4551
4552
4553
4558
4559
4560
4561
4566
4567
4568
4569
4570
4571
4572
4576
4577
4578
4579
4580
4581
4584
4587
4588
4595
4600
4603
4604
4605
4606
4607
4608
4612
4613
4614
4615
4616
4621
4639
4640
4641
4642
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4660
4661
4662
4663
4664
4665
4666
4685
4686
4687
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4714
4715
4716
4717
4718
4719
4722
4723
4724
4725
4726
4727
4731
4732
4733
4734
4735
4736
4741
4742
4745
4746
4747
4751
4752
4753
4757
4758
4759
4760
4761
4762
4763
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4782
4788
4793
4799
4803
4807
4808
4809
4823
4824
4825
4826
4827
4834
4835
4836
4837
4838
4839
4843
4844
4845
4846
4847
4848
4852
4853
4854
4857
4861
4862
4863
4864
4865
4866
4867
4873
4874
4875
4876
4880
4881
4882
4883
4884
4885
4886
4890
4891
4892
4895
4899
4900
4905
4906
4907
4908
4927
4928
4929
4938
4939
4940
4941
4946
4947
4948
4949
4950
4951
4952
4953
4954
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4989
4990
4993
4994
4997
4998
5001
5002
5005
5006
5009
5010
5014
5015
5024
5025
5028
5029
5030
5034
5035
5038
5039
5042
5043
5044
5049
5050
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5071
5075
5085
5086
5087
5088
5089
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5176
5177
5180
5181
5186
5187
5193
5194
5195
5201
5202
5203
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5236
5237
5238
5243
5247
5248
5249
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5269
5270
5271
5274
5278
5279
5280
5283
5286
5288
5289
5290
5291
5292
5293
5294
5300
5301
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5320
5321
5322
5323
5324
5325
5328
5331
5332
5335
5338
5339
5340
5342
5343
5344
5345
5346
5347
5348
5349
5350
5357
5358
5359
5363
5364
5365
5366
5367
5371
5372
5373
5374
5375
5376
5377
5378
5381
5382
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5402
5406
5419
5432
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5462
5467
5468
5473
5478
5479
5480
5481
5484
5487
5488
5489
5490
5491
5500
5501
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5523
5524
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5576
5577
5578
5583
5584
5585
5586
5587
5588
5589
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5606
5607
/* ... */
#define BTSTACK_FILE__ "sm.c"
#include <string.h>
#include <inttypes.h>
#include "ble/le_device_db.h"
#include "ble/core.h"
#include "ble/sm.h"
#include "bluetooth_company_id.h"
#include "btstack_bool.h"
#include "btstack_crypto.h"
#include "btstack_debug.h"
#include "btstack_event.h"
#include "btstack_linked_list.h"
#include "btstack_memory.h"
#include "btstack_tlv.h"
#include "gap.h"
#include "hci.h"
#include "hci_dump.h"
#include "l2cap.h"
17 includes
#if !defined(ENABLE_LE_PERIPHERAL) && !defined(ENABLE_LE_CENTRAL)
#error "LE Security Manager used, but neither ENABLE_LE_PERIPHERAL nor ENABLE_LE_CENTRAL defined. Please add at least one to btstack_config.h."
#endif
#if defined(ENABLE_CROSS_TRANSPORT_KEY_DERIVATION) && (!defined(ENABLE_CLASSIC) || !defined(ENABLE_LE_SECURE_CONNECTIONS))
#error "Cross Transport Key Derivation requires support for LE Secure Connections and BR/EDR (Classic)"
#endif
#ifdef ENABLE_LE_SECURE_CONNECTIONS
#if HCI_ACL_PAYLOAD_SIZE < 69
#error "HCI_ACL_PAYLOAD_SIZE must be at least 69 bytes when using LE Secure Conection. Please increase HCI_ACL_PAYLOAD_SIZE or disable ENABLE_LE_SECURE_CONNECTIONS"
#endif/* ... */
#endif
#if defined(ENABLE_LE_PERIPHERAL) && defined(ENABLE_LE_CENTRAL)
#define IS_RESPONDER(role) ((role) == HCI_ROLE_SLAVE)
#else
#ifdef ENABLE_LE_CENTRAL
#define IS_RESPONDER(role) (0 && ((role) == HCI_ROLE_SLAVE))
/* ... */#else
#define IS_RESPONDER(role) (1 || ((role) == HCI_ROLE_SLAVE))
/* ... */#endif/* ... */
#endif
#if defined(ENABLE_LE_SIGNED_WRITE) || defined(ENABLE_LE_SECURE_CONNECTIONS)
#define USE_CMAC_ENGINE
#endif
#define BTSTACK_TAG32(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))
typedef enum {
DKG_W4_WORKING,
DKG_CALC_IRK,
DKG_CALC_DHK,
DKG_READY
...} derived_key_generation_t;
typedef enum {
RAU_IDLE,
RAU_GET_RANDOM,
RAU_W4_RANDOM,
RAU_GET_ENC,
RAU_W4_ENC,
...} random_address_update_t;
typedef enum {
CMAC_IDLE,
CMAC_CALC_SUBKEYS,
CMAC_W4_SUBKEYS,
CMAC_CALC_MI,
CMAC_W4_MI,
CMAC_CALC_MLAST,
CMAC_W4_MLAST
...} cmac_state_t;
typedef enum {
JUST_WORKS,
PK_RESP_INPUT,
PK_INIT_INPUT,
PK_BOTH_INPUT,
NUMERIC_COMPARISON,
OOB
...} stk_generation_method_t;
typedef enum {
SM_USER_RESPONSE_IDLE,
SM_USER_RESPONSE_PENDING,
SM_USER_RESPONSE_CONFIRM,
SM_USER_RESPONSE_PASSKEY,
SM_USER_RESPONSE_DECLINE
...} sm_user_response_t;
typedef enum {
SM_AES128_IDLE,
SM_AES128_ACTIVE
...} sm_aes128_state_t;
typedef enum {
ADDRESS_RESOLUTION_IDLE,
ADDRESS_RESOLUTION_GENERAL,
ADDRESS_RESOLUTION_FOR_CONNECTION,
...} address_resolution_mode_t;
typedef enum {
ADDRESS_RESOLUTION_SUCCEEDED,
ADDRESS_RESOLUTION_FAILED,
...} address_resolution_event_t;
typedef enum {
EC_KEY_GENERATION_IDLE,
EC_KEY_GENERATION_ACTIVE,
EC_KEY_GENERATION_DONE,
...} ec_key_generation_state_t;
typedef enum {
SM_STATE_VAR_DHKEY_NEEDED = 1 << 0,
SM_STATE_VAR_DHKEY_CALCULATED = 1 << 1,
SM_STATE_VAR_DHKEY_COMMAND_RECEIVED = 1 << 2,
...} sm_state_var_t;
typedef enum {
SM_SC_OOB_IDLE,
SM_SC_OOB_W4_RANDOM,
SM_SC_OOB_W2_CALC_CONFIRM,
SM_SC_OOB_W4_CONFIRM,
...} sm_sc_oob_state_t;
typedef uint8_t sm_key24_t[3];
typedef uint8_t sm_key56_t[7];
typedef uint8_t sm_key256_t[32];
static bool sm_initialized;
static bool test_use_fixed_local_csrk;
static bool test_use_fixed_local_irk;
#ifdef ENABLE_TESTING_SUPPORT
static uint8_t test_pairing_failure;
#endif
static uint8_t sm_accepted_stk_generation_methods;
static uint8_t sm_max_encryption_key_size;
static uint8_t sm_min_encryption_key_size;
static uint8_t sm_auth_req = 0;
static uint8_t sm_io_capabilities = IO_CAPABILITY_NO_INPUT_NO_OUTPUT;
static uint32_t sm_fixed_passkey_in_display_role;
static bool sm_reconstruct_ltk_without_le_device_db_entry;
#ifdef ENABLE_LE_PERIPHERAL
static bool sm_slave_request_security;
#endif
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static bool sm_sc_only_mode;
static uint8_t sm_sc_oob_random[16];
static void (*sm_sc_oob_callback)(const uint8_t * confirm_value, const uint8_t * random_value);
static sm_sc_oob_state_t sm_sc_oob_state;
#ifdef ENABLE_LE_SECURE_CONNECTIONS_DEBUG_KEY
static bool sm_sc_debug_keys_enabled;
#endif/* ... */
#endif
static bool sm_persistent_keys_random_active;
static const btstack_tlv_t * sm_tlv_impl;
static void * sm_tlv_context;
static sm_key_t sm_persistent_er;
static sm_key_t sm_persistent_ir;
static sm_key_t sm_persistent_dhk;
static sm_key_t sm_persistent_irk;
static derived_key_generation_t dkg_state;
static random_address_update_t rau_state;
static bd_addr_t sm_random_address;
#ifdef USE_CMAC_ENGINE
static btstack_crypto_aes128_cmac_t sm_cmac_request;
static void (*sm_cmac_done_callback)(uint8_t hash[8]);
static uint8_t sm_cmac_active;
static uint8_t sm_cmac_hash[16];/* ... */
#endif
#ifdef ENABLE_LE_SIGNED_WRITE
static uint16_t sm_cmac_signed_write_message_len;
static uint8_t sm_cmac_signed_write_header[3];
static const uint8_t * sm_cmac_signed_write_message;
static uint8_t sm_cmac_signed_write_sign_counter[4];/* ... */
#endif
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static sm_connection_t * sm_cmac_connection;
static uint8_t sm_cmac_sc_buffer[80];/* ... */
#endif
static int sm_address_resolution_test;
static uint8_t sm_address_resolution_addr_type;
static bd_addr_t sm_address_resolution_address;
static void * sm_address_resolution_context;
static address_resolution_mode_t sm_address_resolution_mode;
static btstack_linked_list_t sm_address_resolution_general_queue;
static sm_aes128_state_t sm_aes128_state;
static btstack_crypto_random_t sm_crypto_random_request;
static btstack_crypto_aes128_t sm_crypto_aes128_request;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static btstack_crypto_ecc_p256_t sm_crypto_ecc_p256_request;
#endif
static uint8_t sm_random_data[8];
static uint8_t sm_aes128_key[16];
static uint8_t sm_aes128_plaintext[16];
static uint8_t sm_aes128_ciphertext[16];
static btstack_packet_callback_registration_t hci_event_callback_registration;
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
static btstack_packet_callback_registration_t l2cap_event_callback_registration;
#endif
static btstack_linked_list_t sm_event_handlers;
static btstack_timer_source_t sm_run_timer;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static ec_key_generation_state_t ec_key_generation_state;
static uint8_t ec_q[64];/* ... */
#endif
typedef struct sm_setup_context {
btstack_timer_source_t sm_timeout;
uint8_t sm_user_response;
uint8_t sm_keypress_notification;
uint8_t sm_key_distribution_send_set;
uint8_t sm_key_distribution_sent_set;
uint8_t sm_key_distribution_expected_set;
uint8_t sm_key_distribution_received_set;
stk_generation_method_t sm_stk_generation_method;
sm_key_t sm_tk;
uint8_t sm_have_oob_data;
bool sm_use_secure_connections;
sm_key_t sm_c1_t3_value;
sm_pairing_packet_t sm_m_preq;
sm_pairing_packet_t sm_s_pres;
sm_key_t sm_local_random;
sm_key_t sm_local_confirm;
sm_key_t sm_peer_random;
sm_key_t sm_peer_confirm;
uint8_t sm_m_addr_type;
uint8_t sm_s_addr_type;
bd_addr_t sm_m_address;
bd_addr_t sm_s_address;
sm_key_t sm_ltk;
uint8_t sm_state_vars;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
uint8_t sm_peer_q[64];
sm_key_t sm_peer_nonce;
sm_key_t sm_local_nonce;
uint8_t sm_dhkey[32];
sm_key_t sm_peer_dhkey_check;
sm_key_t sm_local_dhkey_check;
sm_key_t sm_ra;
sm_key_t sm_rb;
sm_key_t sm_t;
sm_key_t sm_mackey;
uint8_t sm_passkey_bit; /* ... */
#endif
uint16_t sm_local_y;
uint16_t sm_local_div;
uint16_t sm_local_ediv;
uint8_t sm_local_rand[8];
sm_key_t sm_local_ltk;
sm_key_t sm_local_csrk;
sm_key_t sm_local_irk;
uint16_t sm_peer_y;
uint16_t sm_peer_div;
uint16_t sm_peer_ediv;
uint8_t sm_peer_rand[8];
sm_key_t sm_peer_ltk;
sm_key_t sm_peer_irk;
sm_key_t sm_peer_csrk;
uint8_t sm_peer_addr_type;
bd_addr_t sm_peer_address;
#ifdef ENABLE_LE_SIGNED_WRITE
int sm_le_device_index;
#endif
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
link_key_t sm_link_key;
link_key_type_t sm_link_key_type;/* ... */
#endif
...} sm_setup_context_t;
static sm_setup_context_t the_setup;
static sm_setup_context_t * setup = &the_setup;
static uint16_t sm_active_connection_handle = HCI_CON_HANDLE_INVALID;
static int (*sm_get_oob_data)(uint8_t addres_type, bd_addr_t addr, uint8_t * oob_data) = NULL;
static int (*sm_get_sc_oob_data)(uint8_t addres_type, bd_addr_t addr, uint8_t * oob_sc_peer_confirm, uint8_t * oob_sc_peer_random);
static bool (*sm_get_ltk_callback)(hci_con_handle_t con_handle, uint8_t addres_type, bd_addr_t addr, uint8_t * ltk);
static void sm_run(void);
static void sm_state_reset(void);
static void sm_done_for_handle(hci_con_handle_t con_handle);
static sm_connection_t * sm_get_connection_for_handle(hci_con_handle_t con_handle);
static void sm_cache_ltk(sm_connection_t * connection, const sm_key_t ltk);
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
static sm_connection_t * sm_get_connection_for_bd_addr_and_type(bd_addr_t address, bd_addr_type_t addr_type);
#endif
static inline int sm_calc_actual_encryption_key_size(int other);
static int sm_validate_stk_generation_method(void);
static void sm_handle_encryption_result_address_resolution(void *arg);
static void sm_handle_encryption_result_dkg_dhk(void *arg);
static void sm_handle_encryption_result_dkg_irk(void *arg);
static void sm_handle_encryption_result_enc_a(void *arg);
static void sm_handle_encryption_result_enc_b(void *arg);
static void sm_handle_encryption_result_enc_c(void *arg);
static void sm_handle_encryption_result_enc_csrk(void *arg);
static void sm_handle_encryption_result_enc_d(void * arg);
static void sm_handle_encryption_result_enc_ph3_ltk(void *arg);
static void sm_handle_encryption_result_enc_ph3_y(void *arg);
#ifdef ENABLE_LE_PERIPHERAL
static void sm_handle_encryption_result_enc_ph4_ltk(void *arg);
static void sm_handle_encryption_result_enc_ph4_y(void *arg);/* ... */
#endif
static void sm_handle_encryption_result_enc_stk(void *arg);
static void sm_handle_encryption_result_rau(void *arg);
static void sm_handle_random_result_ph2_tk(void * arg);
static void sm_handle_random_result_rau(void * arg);
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static void sm_cmac_message_start(const sm_key_t key, uint16_t message_len, const uint8_t * message, void (*done_callback)(uint8_t * hash));
static void sm_ec_generate_new_key(void);
static void sm_handle_random_result_sc_next_w2_cmac_for_confirmation(void * arg);
static void sm_handle_random_result_sc_next_send_pairing_random(void * arg);
static bool sm_passkey_entry(stk_generation_method_t method);/* ... */
#endif
static void sm_pairing_complete(sm_connection_t * sm_conn, uint8_t status, uint8_t reason);
static void log_info_hex16(const char * name, uint16_t value){
log_info("%-6s 0x%04x", name, value);
}{ ... }
static inline uint8_t sm_pairing_packet_get_io_capability(sm_pairing_packet_t packet){
return packet[1];
}{ ... }
static inline uint8_t sm_pairing_packet_get_oob_data_flag(sm_pairing_packet_t packet){
return packet[2];
}{ ... }
static inline uint8_t sm_pairing_packet_get_auth_req(sm_pairing_packet_t packet){
return packet[3];
}{ ... }
static inline uint8_t sm_pairing_packet_get_max_encryption_key_size(sm_pairing_packet_t packet){
return packet[4];
}{ ... }
static inline uint8_t sm_pairing_packet_get_initiator_key_distribution(sm_pairing_packet_t packet){
return packet[5];
}{ ... }
static inline uint8_t sm_pairing_packet_get_responder_key_distribution(sm_pairing_packet_t packet){
return packet[6];
}{ ... }
static inline void sm_pairing_packet_set_code(sm_pairing_packet_t packet, uint8_t code){
packet[0] = code;
}{ ... }
static inline void sm_pairing_packet_set_io_capability(sm_pairing_packet_t packet, uint8_t io_capability){
packet[1] = io_capability;
}{ ... }
static inline void sm_pairing_packet_set_oob_data_flag(sm_pairing_packet_t packet, uint8_t oob_data_flag){
packet[2] = oob_data_flag;
}{ ... }
static inline void sm_pairing_packet_set_auth_req(sm_pairing_packet_t packet, uint8_t auth_req){
packet[3] = auth_req;
}{ ... }
static inline void sm_pairing_packet_set_max_encryption_key_size(sm_pairing_packet_t packet, uint8_t max_encryption_key_size){
packet[4] = max_encryption_key_size;
}{ ... }
static inline void sm_pairing_packet_set_initiator_key_distribution(sm_pairing_packet_t packet, uint8_t initiator_key_distribution){
packet[5] = initiator_key_distribution;
}{ ... }
static inline void sm_pairing_packet_set_responder_key_distribution(sm_pairing_packet_t packet, uint8_t responder_key_distribution){
packet[6] = responder_key_distribution;
}{ ... }
static bool sm_is_null_random(uint8_t random[8]){
return btstack_is_null(random, 8);
}{ ... }
static bool sm_is_null_key(uint8_t * key){
return btstack_is_null(key, 16);
}{ ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static bool sm_is_ff(const uint8_t * buffer, uint16_t size){
uint16_t i;
for (i=0; i < size ; i++){
if (buffer[i] != 0xff) {
return false;
}if (buffer[i] != 0xff) { ... }
}for (i=0; i < size ; i++) { ... }
return true;
}sm_is_ff (const uint8_t * buffer, uint16_t size) { ... }
/* ... */#endif
static void sm_run_timer_handler(btstack_timer_source_t * ts){
UNUSED(ts);
sm_run();
}{ ... }
static void sm_trigger_run(void){
if (!sm_initialized) return;
(void)btstack_run_loop_remove_timer(&sm_run_timer);
btstack_run_loop_set_timer(&sm_run_timer, 0);
btstack_run_loop_add_timer(&sm_run_timer);
}{ ... }
static void sm_reset_tk(void){
int i;
for (i=0;i<16;i++){
setup->sm_tk[i] = 0;
}for (i=0;i<16;i++) { ... }
}{ ... }
static void sm_truncate_key(sm_key_t key, int max_encryption_size){
int i;
for (i = max_encryption_size ; i < 16 ; i++){
key[15-i] = 0;
}for (i = max_encryption_size ; i < 16 ; i++) { ... }
}{ ... }
static void sm_er_ir_set_default(void){
int i;
for (i=0;i<16;i++){
sm_persistent_er[i] = 0x30 + i;
sm_persistent_ir[i] = 0x90 + i;
}for (i=0;i<16;i++) { ... }
}{ ... }
static bool sm_er_is_default(void){
int i;
for (i=0;i<16;i++){
if (sm_persistent_er[i] != (0x30+i)) return true;
}for (i=0;i<16;i++) { ... }
return false;
}{ ... }
static bool sm_ir_is_default(void){
int i;
for (i=0;i<16;i++){
if (sm_persistent_ir[i] != (0x90+i)) return true;
}for (i=0;i<16;i++) { ... }
return false;
}{ ... }
static void sm_dispatch_event(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){
UNUSED(channel);
hci_dump_btstack_event(packet, size);
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &sm_event_handlers);
while (btstack_linked_list_iterator_has_next(&it)){
btstack_packet_callback_registration_t * entry = (btstack_packet_callback_registration_t*) btstack_linked_list_iterator_next(&it);
entry->callback(packet_type, 0, packet, size);
}while (btstack_linked_list_iterator_has_next(&it)) { ... }
}{ ... }
static void sm_setup_event_base(uint8_t * event, int event_size, uint8_t type, hci_con_handle_t con_handle, uint8_t addr_type, bd_addr_t address){
event[0] = type;
event[1] = event_size - 2;
little_endian_store_16(event, 2, con_handle);
event[4] = addr_type;
reverse_bd_addr(address, &event[5]);
}{ ... }
static void sm_notify_client_base(uint8_t type, hci_con_handle_t con_handle, uint8_t addr_type, bd_addr_t address){
uint8_t event[11];
sm_setup_event_base(event, sizeof(event), type, con_handle, addr_type, address);
sm_dispatch_event(HCI_EVENT_PACKET, 0, event, sizeof(event));
}{ ... }
static void sm_notify_client_index(uint8_t type, hci_con_handle_t con_handle, uint8_t addr_type, bd_addr_t address, uint16_t index){
bd_addr_t identity_address;
int identity_address_type;
le_device_db_info(index, &identity_address_type, identity_address, NULL);
uint8_t event[20];
sm_setup_event_base(event, sizeof(event), type, con_handle, addr_type, address);
event[11] = identity_address_type;
reverse_bd_addr(identity_address, &event[12]);
little_endian_store_16(event, 18, index);
sm_dispatch_event(HCI_EVENT_PACKET, 0, event, sizeof(event));
}{ ... }
static void sm_notify_client_status(uint8_t type, hci_con_handle_t con_handle, uint8_t addr_type, bd_addr_t address, uint8_t status){
uint8_t event[12];
sm_setup_event_base(event, sizeof(event), type, con_handle, addr_type, address);
event[11] = status;
sm_dispatch_event(HCI_EVENT_PACKET, 0, (uint8_t*) &event, sizeof(event));
}{ ... }
static void sm_reencryption_started(sm_connection_t * sm_conn){
if (sm_conn->sm_reencryption_active) return;
sm_conn->sm_reencryption_active = true;
int identity_addr_type;
bd_addr_t identity_addr;
if (sm_conn->sm_le_db_index >= 0){
le_device_db_info(sm_conn->sm_le_db_index, &identity_addr_type, identity_addr, NULL);
}if (sm_conn->sm_le_db_index >= 0) { ... } else {
identity_addr_type = sm_conn->sm_peer_addr_type;
memcpy(identity_addr, sm_conn->sm_peer_address, 6);
}else { ... }
sm_notify_client_base(SM_EVENT_REENCRYPTION_STARTED, sm_conn->sm_handle, identity_addr_type, identity_addr);
}{ ... }
static void sm_reencryption_complete(sm_connection_t * sm_conn, uint8_t status){
if (!sm_conn->sm_reencryption_active) return;
sm_conn->sm_reencryption_active = false;
int identity_addr_type;
bd_addr_t identity_addr;
if (sm_conn->sm_le_db_index >= 0){
le_device_db_info(sm_conn->sm_le_db_index, &identity_addr_type, identity_addr, NULL);
}if (sm_conn->sm_le_db_index >= 0) { ... } else {
identity_addr_type = sm_conn->sm_peer_addr_type;
memcpy(identity_addr, sm_conn->sm_peer_address, 6);
}else { ... }
sm_notify_client_status(SM_EVENT_REENCRYPTION_COMPLETE, sm_conn->sm_handle, identity_addr_type, identity_addr, status);
}{ ... }
static void sm_pairing_started(sm_connection_t * sm_conn){
if (sm_conn->sm_pairing_active) return;
sm_conn->sm_pairing_active = true;
uint8_t event[11];
sm_setup_event_base(event, sizeof(event), SM_EVENT_PAIRING_STARTED, sm_conn->sm_handle, setup->sm_peer_addr_type, setup->sm_peer_address);
sm_dispatch_event(HCI_EVENT_PACKET, 0, (uint8_t*) &event, sizeof(event));
}{ ... }
static void sm_pairing_complete(sm_connection_t * sm_conn, uint8_t status, uint8_t reason){
if (!sm_conn->sm_pairing_active) return;
sm_conn->sm_pairing_active = false;
uint8_t event[13];
sm_setup_event_base(event, sizeof(event), SM_EVENT_PAIRING_COMPLETE, sm_conn->sm_handle, setup->sm_peer_addr_type, setup->sm_peer_address);
event[11] = status;
event[12] = reason;
sm_dispatch_event(HCI_EVENT_PACKET, 0, (uint8_t*) &event, sizeof(event));
}{ ... }
static void sm_timeout_handler(btstack_timer_source_t * timer){
log_info("SM timeout");
sm_connection_t * sm_conn = (sm_connection_t*) btstack_run_loop_get_timer_context(timer);
sm_conn->sm_engine_state = SM_GENERAL_TIMEOUT;
sm_reencryption_complete(sm_conn, ERROR_CODE_CONNECTION_TIMEOUT);
sm_pairing_complete(sm_conn, ERROR_CODE_CONNECTION_TIMEOUT, 0);
sm_done_for_handle(sm_conn->sm_handle);
sm_run();
}{ ... }
static void sm_timeout_start(sm_connection_t * sm_conn){
btstack_run_loop_remove_timer(&setup->sm_timeout);
btstack_run_loop_set_timer_context(&setup->sm_timeout, sm_conn);
btstack_run_loop_set_timer_handler(&setup->sm_timeout, sm_timeout_handler);
btstack_run_loop_set_timer(&setup->sm_timeout, 30000);
btstack_run_loop_add_timer(&setup->sm_timeout);
}{ ... }
static void sm_timeout_stop(void){
btstack_run_loop_remove_timer(&setup->sm_timeout);
}{ ... }
static void sm_timeout_reset(sm_connection_t * sm_conn){
sm_timeout_stop();
sm_timeout_start(sm_conn);
}{ ... }
static gap_random_address_type_t gap_random_adress_type;
static btstack_timer_source_t gap_random_address_update_timer;
static uint32_t gap_random_adress_update_period;
static void gap_random_address_trigger(void){
log_info("gap_random_address_trigger, state %u", rau_state);
if (rau_state != RAU_IDLE) return;
rau_state = RAU_GET_RANDOM;
sm_trigger_run();
}{ ... }
static void gap_random_address_update_handler(btstack_timer_source_t * timer){
UNUSED(timer);
log_info("GAP Random Address Update due");
btstack_run_loop_set_timer(&gap_random_address_update_timer, gap_random_adress_update_period);
btstack_run_loop_add_timer(&gap_random_address_update_timer);
gap_random_address_trigger();
}{ ... }
static void gap_random_address_update_start(void){
btstack_run_loop_set_timer_handler(&gap_random_address_update_timer, gap_random_address_update_handler);
btstack_run_loop_set_timer(&gap_random_address_update_timer, gap_random_adress_update_period);
btstack_run_loop_add_timer(&gap_random_address_update_timer);
}{ ... }
static void gap_random_address_update_stop(void){
btstack_run_loop_remove_timer(&gap_random_address_update_timer);
}{ ... }
static void sm_ah_r_prime(uint8_t r[3], uint8_t * r_prime){
memset(r_prime, 0, 16);
(void)memcpy(&r_prime[13], r, 3);
}{ ... }
static void sm_d1_d_prime(uint16_t d, uint16_t r, uint8_t * d1_prime){
memset(d1_prime, 0, 16);
big_endian_store_16(d1_prime, 12, r);
big_endian_store_16(d1_prime, 14, d);
}{ ... }
static void sm_c1_t1(sm_key_t r, uint8_t preq[7], uint8_t pres[7], uint8_t iat, uint8_t rat, uint8_t * t1){
sm_key_t p1;
reverse_56(pres, &p1[0]);
reverse_56(preq, &p1[7]);
p1[14] = rat;
p1[15] = iat;
log_info_key("p1", p1);
log_info_key("r", r);
int i;
for (i=0;i<16;i++){
t1[i] = r[i] ^ p1[i];
}for (i=0;i<16;i++) { ... }
log_info_key("t1", t1);
}{ ... }
static void sm_c1_t3(sm_key_t t2, bd_addr_t ia, bd_addr_t ra, uint8_t * t3){
sm_key_t p2;
memset(p2, 0, 16);
(void)memcpy(&p2[4], ia, 6);
(void)memcpy(&p2[10], ra, 6);
log_info_key("p2", p2);
int i;
for (i=0;i<16;i++){
t3[i] = t2[i] ^ p2[i];
}for (i=0;i<16;i++) { ... }
log_info_key("t3", t3);
}{ ... }
static void sm_s1_r_prime(sm_key_t r1, sm_key_t r2, uint8_t * r_prime){
log_info_key("r1", r1);
log_info_key("r2", r2);
(void)memcpy(&r_prime[8], &r2[8], 8);
(void)memcpy(&r_prime[0], &r1[8], 8);
}{ ... }
static void sm_setup_tk(void){
static const stk_generation_method_t stk_generation_method [5] [5] = {
{ JUST_WORKS, JUST_WORKS, PK_INIT_INPUT, JUST_WORKS, PK_INIT_INPUT },
{ JUST_WORKS, JUST_WORKS, PK_INIT_INPUT, JUST_WORKS, PK_INIT_INPUT },
{ PK_RESP_INPUT, PK_RESP_INPUT, PK_BOTH_INPUT, JUST_WORKS, PK_RESP_INPUT },
{ JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS },
{ PK_RESP_INPUT, PK_RESP_INPUT, PK_INIT_INPUT, JUST_WORKS, PK_RESP_INPUT },
...};
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static const stk_generation_method_t stk_generation_method_with_secure_connection[5][5] = {
{ JUST_WORKS, JUST_WORKS, PK_INIT_INPUT, JUST_WORKS, PK_INIT_INPUT },
{ JUST_WORKS, NUMERIC_COMPARISON, PK_INIT_INPUT, JUST_WORKS, NUMERIC_COMPARISON },
{ PK_RESP_INPUT, PK_RESP_INPUT, PK_BOTH_INPUT, JUST_WORKS, PK_RESP_INPUT },
{ JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS },
{ PK_RESP_INPUT, NUMERIC_COMPARISON, PK_INIT_INPUT, JUST_WORKS, NUMERIC_COMPARISON },
...};/* ... */
#endif
setup->sm_stk_generation_method = JUST_WORKS;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
setup->sm_use_secure_connections = ( sm_pairing_packet_get_auth_req(setup->sm_m_preq)
& sm_pairing_packet_get_auth_req(setup->sm_s_pres)
& SM_AUTHREQ_SECURE_CONNECTION ) != 0u;/* ... */
#else
setup->sm_use_secure_connections = false;
#endif
log_info("Secure pairing: %u", setup->sm_use_secure_connections);
bool use_oob;
if (setup->sm_use_secure_connections){
use_oob = (sm_pairing_packet_get_oob_data_flag(setup->sm_m_preq) | sm_pairing_packet_get_oob_data_flag(setup->sm_s_pres)) != 0;
}if (setup->sm_use_secure_connections) { ... } else {
use_oob = (sm_pairing_packet_get_oob_data_flag(setup->sm_m_preq) & sm_pairing_packet_get_oob_data_flag(setup->sm_s_pres)) != 0;
}else { ... }
if (use_oob){
log_info("SM: have OOB data");
log_info_key("OOB", setup->sm_tk);
setup->sm_stk_generation_method = OOB;
return;
}if (use_oob) { ... }
if (((sm_pairing_packet_get_auth_req(setup->sm_m_preq) & SM_AUTHREQ_MITM_PROTECTION) == 0u)
&& ((sm_pairing_packet_get_auth_req(setup->sm_s_pres) & SM_AUTHREQ_MITM_PROTECTION) == 0u)){
log_info("SM: MITM not required by both -> JUST WORKS");
return;
}if (((sm_pairing_packet_get_auth_req(setup->sm_m_preq) & SM_AUTHREQ_MITM_PROTECTION) == 0u) && ((sm_pairing_packet_get_auth_req(setup->sm_s_pres) & SM_AUTHREQ_MITM_PROTECTION) == 0u)) { ... }
sm_reset_tk();
if ((sm_pairing_packet_get_io_capability(setup->sm_m_preq) > IO_CAPABILITY_KEYBOARD_DISPLAY) || (sm_pairing_packet_get_io_capability(setup->sm_s_pres) > IO_CAPABILITY_KEYBOARD_DISPLAY)){
return;
}if ((sm_pairing_packet_get_io_capability(setup->sm_m_preq) > IO_CAPABILITY_KEYBOARD_DISPLAY) || (sm_pairing_packet_get_io_capability(setup->sm_s_pres) > IO_CAPABILITY_KEYBOARD_DISPLAY)) { ... }
const stk_generation_method_t (*generation_method)[5] = stk_generation_method;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (setup->sm_use_secure_connections){
generation_method = stk_generation_method_with_secure_connection;
}if (setup->sm_use_secure_connections) { ... }
/* ... */#endif
setup->sm_stk_generation_method = generation_method[sm_pairing_packet_get_io_capability(setup->sm_s_pres)][sm_pairing_packet_get_io_capability(setup->sm_m_preq)];
log_info("sm_setup_tk: master io cap: %u, slave io cap: %u -> method %u",
sm_pairing_packet_get_io_capability(setup->sm_m_preq), sm_pairing_packet_get_io_capability(setup->sm_s_pres), setup->sm_stk_generation_method);
}{ ... }
static int sm_key_distribution_flags_for_set(uint8_t key_set){
int flags = 0;
if ((key_set & SM_KEYDIST_ENC_KEY) != 0u){
flags |= SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION;
flags |= SM_KEYDIST_FLAG_MASTER_IDENTIFICATION;
}if ((key_set & SM_KEYDIST_ENC_KEY) != 0u) { ... }
if ((key_set & SM_KEYDIST_ID_KEY) != 0u){
flags |= SM_KEYDIST_FLAG_IDENTITY_INFORMATION;
flags |= SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION;
}if ((key_set & SM_KEYDIST_ID_KEY) != 0u) { ... }
if ((key_set & SM_KEYDIST_SIGN) != 0u){
flags |= SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION;
}if ((key_set & SM_KEYDIST_SIGN) != 0u) { ... }
return flags;
}{ ... }
static void sm_setup_key_distribution(uint8_t keys_to_send, uint8_t keys_to_receive){
setup->sm_key_distribution_received_set = 0;
setup->sm_key_distribution_expected_set = sm_key_distribution_flags_for_set(keys_to_receive);
setup->sm_key_distribution_send_set = sm_key_distribution_flags_for_set(keys_to_send);
setup->sm_key_distribution_sent_set = 0;
#ifdef ENABLE_LE_SIGNED_WRITE
setup->sm_le_device_index = -1;
#endif
}{ ... }
static bool sm_address_resolution_idle(void){
return sm_address_resolution_mode == ADDRESS_RESOLUTION_IDLE;
}{ ... }
static void sm_address_resolution_start_lookup(uint8_t addr_type, hci_con_handle_t con_handle, bd_addr_t addr, address_resolution_mode_t mode, void * context){
(void)memcpy(sm_address_resolution_address, addr, 6);
sm_address_resolution_addr_type = addr_type;
sm_address_resolution_test = 0;
sm_address_resolution_mode = mode;
sm_address_resolution_context = context;
sm_notify_client_base(SM_EVENT_IDENTITY_RESOLVING_STARTED, con_handle, addr_type, addr);
}{ ... }
int sm_address_resolution_lookup(uint8_t address_type, bd_addr_t address){
btstack_linked_list_iterator_t it;
sm_lookup_entry_t * entry;
btstack_linked_list_iterator_init(&it, &sm_address_resolution_general_queue);
while(btstack_linked_list_iterator_has_next(&it)){
entry = (sm_lookup_entry_t *) btstack_linked_list_iterator_next(&it);
if (entry->address_type != address_type) continue;
if (memcmp(entry->address, address, 6) != 0) continue;
return BTSTACK_BUSY;
}while (btstack_linked_list_iterator_has_next(&it)) { ... }
entry = btstack_memory_sm_lookup_entry_get();
if (!entry) return BTSTACK_MEMORY_ALLOC_FAILED;
entry->address_type = (bd_addr_type_t) address_type;
(void)memcpy(entry->address, address, 6);
btstack_linked_list_add(&sm_address_resolution_general_queue, (btstack_linked_item_t *) entry);
sm_trigger_run();
return 0;
}{ ... }
#ifdef USE_CMAC_ENGINE
static void sm_cmac_done_trampoline(void * arg){
UNUSED(arg);
sm_cmac_active = 0;
(*sm_cmac_done_callback)(sm_cmac_hash);
sm_trigger_run();
}sm_cmac_done_trampoline (void * arg) { ... }
int sm_cmac_ready(void){
return sm_cmac_active == 0u;
}sm_cmac_ready (void) { ... }
/* ... */#endif
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static void sm_cmac_message_start(const sm_key_t key, uint16_t message_len, const uint8_t * message, void (*done_callback)(uint8_t * hash)){
sm_cmac_active = 1;
sm_cmac_done_callback = done_callback;
btstack_crypto_aes128_cmac_message(&sm_cmac_request, key, message_len, message, sm_cmac_hash, sm_cmac_done_trampoline, NULL);
}sm_cmac_message_start (const sm_key_t key, uint16_t message_len, const uint8_t * message, void (*done_callback)(uint8_t * hash)) { ... }
/* ... */#endif
#ifdef ENABLE_LE_SIGNED_WRITE
static void sm_cmac_generator_start(const sm_key_t key, uint16_t message_len, uint8_t (*get_byte_callback)(uint16_t offset), void (*done_callback)(uint8_t * hash)){
sm_cmac_active = 1;
sm_cmac_done_callback = done_callback;
btstack_crypto_aes128_cmac_generator(&sm_cmac_request, key, message_len, get_byte_callback, sm_cmac_hash, sm_cmac_done_trampoline, NULL);
}sm_cmac_generator_start (const sm_key_t key, uint16_t message_len, uint8_t (*get_byte_callback)(uint16_t offset), void (*done_callback)(uint8_t * hash)) { ... }
static uint8_t sm_cmac_signed_write_message_get_byte(uint16_t offset){
if (offset >= sm_cmac_signed_write_message_len) {
log_error("sm_cmac_signed_write_message_get_byte. out of bounds, access %u, len %u", offset, sm_cmac_signed_write_message_len);
return 0;
}if (offset >= sm_cmac_signed_write_message_len) { ... }
offset = sm_cmac_signed_write_message_len - 1 - offset;
if (offset < 3){
return sm_cmac_signed_write_header[offset];
}if (offset < 3) { ... }
int actual_message_len_incl_header = sm_cmac_signed_write_message_len - 4;
if (offset < actual_message_len_incl_header){
return sm_cmac_signed_write_message[offset - 3];
}if (offset < actual_message_len_incl_header) { ... }
return sm_cmac_signed_write_sign_counter[offset - actual_message_len_incl_header];
}sm_cmac_signed_write_message_get_byte (uint16_t offset) { ... }
void sm_cmac_signed_write_start(const sm_key_t k, uint8_t opcode, hci_con_handle_t con_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t * hash)){
sm_cmac_signed_write_header[0] = opcode;
little_endian_store_16(sm_cmac_signed_write_header, 1, con_handle);
little_endian_store_32(sm_cmac_signed_write_sign_counter, 0, sign_counter);
uint16_t total_message_len = 3 + message_len + 4;
sm_cmac_signed_write_message = message;
sm_cmac_signed_write_message_len = total_message_len;
sm_cmac_generator_start(k, total_message_len, &sm_cmac_signed_write_message_get_byte, done_handler);
}sm_cmac_signed_write_start (const sm_key_t k, uint8_t opcode, hci_con_handle_t con_handle, uint16_t message_len, const uint8_t * message, uint32_t sign_counter, void (*done_handler)(uint8_t * hash)) { ... }
/* ... */#endif
static void sm_trigger_user_response_basic(sm_connection_t * sm_conn, uint8_t event_type){
setup->sm_user_response = SM_USER_RESPONSE_PENDING;
uint8_t event[12];
sm_setup_event_base(event, sizeof(event), event_type, sm_conn->sm_handle, sm_conn->sm_peer_addr_type, sm_conn->sm_peer_address);
event[11] = setup->sm_use_secure_connections ? 1 : 0;
sm_dispatch_event(HCI_EVENT_PACKET, 0, event, sizeof(event));
}{ ... }
static void sm_trigger_user_response_passkey(sm_connection_t * sm_conn, uint8_t event_type){
uint8_t event[16];
uint32_t passkey = big_endian_read_32(setup->sm_tk, 12);
sm_setup_event_base(event, sizeof(event), event_type, sm_conn->sm_handle,
sm_conn->sm_peer_addr_type, sm_conn->sm_peer_address);
event[11] = setup->sm_use_secure_connections ? 1 : 0;
little_endian_store_32(event, 12, passkey);
sm_dispatch_event(HCI_EVENT_PACKET, 0, event, sizeof(event));
}{ ... }
static void sm_trigger_user_response(sm_connection_t * sm_conn){
setup->sm_user_response = SM_USER_RESPONSE_IDLE;
sm_conn->sm_pairing_active = true;
switch (setup->sm_stk_generation_method){
case PK_RESP_INPUT:
if (IS_RESPONDER(sm_conn->sm_role)){
sm_trigger_user_response_basic(sm_conn, SM_EVENT_PASSKEY_INPUT_NUMBER);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
sm_trigger_user_response_passkey(sm_conn, SM_EVENT_PASSKEY_DISPLAY_NUMBER);
}else { ... }
break;case PK_RESP_INPUT:
case PK_INIT_INPUT:
if (IS_RESPONDER(sm_conn->sm_role)){
sm_trigger_user_response_passkey(sm_conn, SM_EVENT_PASSKEY_DISPLAY_NUMBER);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
sm_trigger_user_response_basic(sm_conn, SM_EVENT_PASSKEY_INPUT_NUMBER);
}else { ... }
break;case PK_INIT_INPUT:
case PK_BOTH_INPUT:
sm_trigger_user_response_basic(sm_conn, SM_EVENT_PASSKEY_INPUT_NUMBER);
break;case PK_BOTH_INPUT:
case NUMERIC_COMPARISON:
sm_trigger_user_response_passkey(sm_conn, SM_EVENT_NUMERIC_COMPARISON_REQUEST);
break;case NUMERIC_COMPARISON:
case JUST_WORKS:
sm_trigger_user_response_basic(sm_conn, SM_EVENT_JUST_WORKS_REQUEST);
break;case JUST_WORKS:
case OOB:
break;case OOB:
default:
btstack_assert(false);
break;default
}switch (setup->sm_stk_generation_method) { ... }
}{ ... }
static bool sm_key_distribution_all_received(void) {
log_debug("sm_key_distribution_all_received: received 0x%02x, expecting 0x%02x", setup->sm_key_distribution_received_set, setup->sm_key_distribution_expected_set);
return (setup->sm_key_distribution_expected_set & setup->sm_key_distribution_received_set) == setup->sm_key_distribution_expected_set;
}{ ... }
static void sm_done_for_handle(hci_con_handle_t con_handle){
if (sm_active_connection_handle == con_handle){
sm_timeout_stop();
sm_active_connection_handle = HCI_CON_HANDLE_INVALID;
log_info("sm: connection 0x%x released setup context", con_handle);
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (setup->sm_use_secure_connections){
sm_ec_generate_new_key();
}if (setup->sm_use_secure_connections) { ... }
/* ... */#endif
}if (sm_active_connection_handle == con_handle) { ... }
}{ ... }
static void sm_master_pairing_success(sm_connection_t *connection) {
connection->sm_engine_state = SM_INITIATOR_CONNECTED;
sm_pairing_complete(connection, ERROR_CODE_SUCCESS, 0);
sm_done_for_handle(connection->sm_handle);
}{ ... }
static int sm_key_distribution_flags_for_auth_req(void){
int flags = SM_KEYDIST_ID_KEY;
if ((sm_auth_req & SM_AUTHREQ_BONDING) != 0u){
flags |= SM_KEYDIST_ENC_KEY;
#ifdef ENABLE_LE_SIGNED_WRITE
flags |= SM_KEYDIST_SIGN;
#endif
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
if (hci_classic_supported() && ((sm_auth_req & SM_AUTHREQ_SECURE_CONNECTION) != 0)){
flags |= SM_KEYDIST_LINK_KEY;
}if (hci_classic_supported() && ((sm_auth_req & SM_AUTHREQ_SECURE_CONNECTION) != 0)) { ... }
/* ... */#endif
}if ((sm_auth_req & SM_AUTHREQ_BONDING) != 0u) { ... }
return flags;
}{ ... }
static void sm_reset_setup(void){
setup->sm_state_vars = 0;
setup->sm_keypress_notification = 0;
setup->sm_have_oob_data = 0;
sm_reset_tk();
}{ ... }
static void sm_init_setup(sm_connection_t * sm_conn){
setup->sm_peer_addr_type = sm_conn->sm_peer_addr_type;
(void)memcpy(setup->sm_peer_address, sm_conn->sm_peer_address, 6);
if (sm_get_oob_data != NULL) {
setup->sm_have_oob_data = (*sm_get_oob_data)(sm_conn->sm_peer_addr_type, sm_conn->sm_peer_address, setup->sm_tk);
}if (sm_get_oob_data != NULL) { ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
memset(setup->sm_ra, 0, 16);
memset(setup->sm_rb, 0, 16);
if (setup->sm_have_oob_data && (sm_auth_req & SM_AUTHREQ_SECURE_CONNECTION)){
if (sm_get_sc_oob_data != NULL){
if (IS_RESPONDER(sm_conn->sm_role)){
setup->sm_have_oob_data = (*sm_get_sc_oob_data)(
sm_conn->sm_peer_addr_type,
sm_conn->sm_peer_address,
setup->sm_peer_confirm,
setup->sm_ra);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
setup->sm_have_oob_data = (*sm_get_sc_oob_data)(
sm_conn->sm_peer_addr_type,
sm_conn->sm_peer_address,
setup->sm_peer_confirm,
setup->sm_rb);
}else { ... }
}if (sm_get_sc_oob_data != NULL) { ... } else {
setup->sm_have_oob_data = 0;
}else { ... }
}if (setup->sm_have_oob_data && (sm_auth_req & SM_AUTHREQ_SECURE_CONNECTION)) { ... }
/* ... */#endif
sm_pairing_packet_t * local_packet;
if (IS_RESPONDER(sm_conn->sm_role)){
local_packet = &setup->sm_s_pres;
setup->sm_m_addr_type = sm_conn->sm_peer_addr_type;
setup->sm_s_addr_type = sm_conn->sm_own_addr_type;
(void)memcpy(setup->sm_m_address, sm_conn->sm_peer_address, 6);
(void)memcpy(setup->sm_s_address, sm_conn->sm_own_address, 6);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
local_packet = &setup->sm_m_preq;
setup->sm_s_addr_type = sm_conn->sm_peer_addr_type;
setup->sm_m_addr_type = sm_conn->sm_own_addr_type;
(void)memcpy(setup->sm_s_address, sm_conn->sm_peer_address, 6);
(void)memcpy(setup->sm_m_address, sm_conn->sm_own_address, 6);
uint8_t key_distribution_flags = sm_key_distribution_flags_for_auth_req();
sm_pairing_packet_set_initiator_key_distribution(setup->sm_m_preq, key_distribution_flags);
sm_pairing_packet_set_responder_key_distribution(setup->sm_m_preq, key_distribution_flags);
}else { ... }
log_info("our address %s type %u", bd_addr_to_str(sm_conn->sm_own_address), sm_conn->sm_own_addr_type);
log_info("peer address %s type %u", bd_addr_to_str(sm_conn->sm_peer_address), sm_conn->sm_peer_addr_type);
uint8_t auth_req = sm_auth_req & ~SM_AUTHREQ_CT2;
uint8_t max_encryption_key_size = sm_max_encryption_key_size;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (sm_sc_only_mode){
auth_req |= SM_AUTHREQ_SECURE_CONNECTION;
max_encryption_key_size = 16;
}if (sm_sc_only_mode) { ... }
/* ... */#endif
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
const uint8_t auth_req_for_ct2 = SM_AUTHREQ_SECURE_CONNECTION | SM_AUTHREQ_BONDING;
if ((auth_req & auth_req_for_ct2) == auth_req_for_ct2){
auth_req |= SM_AUTHREQ_CT2;
}if ((auth_req & auth_req_for_ct2) == auth_req_for_ct2) { ... }
/* ... */#endif
sm_pairing_packet_set_io_capability(*local_packet, sm_io_capabilities);
sm_pairing_packet_set_oob_data_flag(*local_packet, setup->sm_have_oob_data);
sm_pairing_packet_set_auth_req(*local_packet, auth_req);
sm_pairing_packet_set_max_encryption_key_size(*local_packet, max_encryption_key_size);
}{ ... }
static int sm_stk_generation_init(sm_connection_t * sm_conn){
sm_pairing_packet_t * remote_packet;
uint8_t keys_to_send;
uint8_t keys_to_receive;
if (IS_RESPONDER(sm_conn->sm_role)){
remote_packet = &setup->sm_m_preq;
keys_to_send = sm_pairing_packet_get_responder_key_distribution(setup->sm_m_preq);
keys_to_receive = sm_pairing_packet_get_initiator_key_distribution(setup->sm_m_preq);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
remote_packet = &setup->sm_s_pres;
keys_to_send = sm_pairing_packet_get_initiator_key_distribution(setup->sm_s_pres);
keys_to_receive = sm_pairing_packet_get_responder_key_distribution(setup->sm_s_pres);
}else { ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (sm_sc_only_mode && (sm_pairing_packet_get_max_encryption_key_size(*remote_packet) < 16)) {
return SM_REASON_ENCRYPTION_KEY_SIZE;
}if (sm_sc_only_mode && (sm_pairing_packet_get_max_encryption_key_size(*remote_packet) < 16)) { ... }
/* ... */#endif
sm_conn->sm_actual_encryption_key_size = sm_calc_actual_encryption_key_size(sm_pairing_packet_get_max_encryption_key_size(*remote_packet));
if (sm_conn->sm_actual_encryption_key_size == 0u) return SM_REASON_ENCRYPTION_KEY_SIZE;
sm_setup_tk();
log_info("SMP: generation method %u", setup->sm_stk_generation_method);
if (!sm_validate_stk_generation_method()) return SM_REASON_AUTHENTHICATION_REQUIREMENTS;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (sm_sc_only_mode && (setup->sm_use_secure_connections == false)){
log_info("SC Only mode active but SC not possible");
return SM_REASON_AUTHENTHICATION_REQUIREMENTS;
}if (sm_sc_only_mode && (setup->sm_use_secure_connections == false)) { ... }
if (setup->sm_use_secure_connections){
keys_to_send &= ~SM_KEYDIST_ENC_KEY;
keys_to_receive &= ~SM_KEYDIST_ENC_KEY;
}if (setup->sm_use_secure_connections) { ... }
/* ... */#endif
sm_setup_key_distribution(keys_to_send, keys_to_receive);
sm_conn->sm_connection_authenticated = (setup->sm_stk_generation_method == JUST_WORKS) ? 0 : 1;
return 0;
}{ ... }
static void sm_address_resolution_handle_event(address_resolution_event_t event){
int matched_device_id = sm_address_resolution_test;
address_resolution_mode_t mode = sm_address_resolution_mode;
void * context = sm_address_resolution_context;
sm_address_resolution_mode = ADDRESS_RESOLUTION_IDLE;
sm_address_resolution_context = NULL;
sm_address_resolution_test = -1;
hci_con_handle_t con_handle = HCI_CON_HANDLE_INVALID;
sm_connection_t * sm_connection;
sm_key_t ltk;
bool have_ltk;
int authenticated;
#ifdef ENABLE_LE_CENTRAL
bool trigger_pairing;
#endif
switch (mode){
case ADDRESS_RESOLUTION_GENERAL:
break;case ADDRESS_RESOLUTION_GENERAL:
case ADDRESS_RESOLUTION_FOR_CONNECTION:
sm_connection = (sm_connection_t *) context;
con_handle = sm_connection->sm_handle;
switch (event){
case ADDRESS_RESOLUTION_SUCCEEDED:
sm_connection->sm_irk_lookup_state = IRK_LOOKUP_SUCCEEDED;
sm_connection->sm_le_db_index = matched_device_id;
log_info("ADDRESS_RESOLUTION_SUCCEEDED, index %d", sm_connection->sm_le_db_index);
le_device_db_encryption_get(sm_connection->sm_le_db_index, NULL, NULL, ltk, NULL, &authenticated, NULL, NULL);
have_ltk = !sm_is_null_key(ltk);
if (IS_RESPONDER(sm_connection->sm_role)) {
#ifdef ENABLE_LE_PERIPHERAL
if (sm_connection->sm_engine_state == SM_RESPONDER_PH0_RECEIVED_LTK_W4_IRK){
sm_connection->sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST;
break;
}if (sm_connection->sm_engine_state == SM_RESPONDER_PH0_RECEIVED_LTK_W4_IRK) { ... }
if (sm_connection->sm_engine_state == SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED_W4_IRK){
sm_connection->sm_engine_state = SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED;
break;
}if (sm_connection->sm_engine_state == SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED_W4_IRK) { ... }
bool trigger_security_request = sm_connection->sm_pairing_requested || sm_slave_request_security;
sm_connection->sm_pairing_requested = false;
#ifdef ENABLE_LE_PROACTIVE_AUTHENTICATION
trigger_security_request = trigger_security_request || have_ltk;/* ... */
#endif
log_info("peripheral: pairing request local %u, have_ltk %u => trigger_security_request %u",
(int) sm_connection->sm_pairing_requested, (int) have_ltk, trigger_security_request);
if (trigger_security_request){
sm_connection->sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST;
if (have_ltk){
sm_reencryption_started(sm_connection);
}if (have_ltk) { ... } else {
sm_pairing_started(sm_connection);
}else { ... }
sm_trigger_run();
}if (trigger_security_request) { ... }
/* ... */#endif
}if (IS_RESPONDER(sm_connection->sm_role)) { ... } else {
#ifdef ENABLE_LE_CENTRAL
trigger_pairing = sm_connection->sm_pairing_requested || sm_connection->sm_security_request_received;
bool auth_required = sm_auth_req & SM_AUTHREQ_MITM_PROTECTION;
log_info("central: pairing request local %u, remote %u => trigger_pairing %u. have_ltk %u",
(int) sm_connection->sm_pairing_requested, (int) sm_connection->sm_security_request_received, (int) trigger_pairing, (int) have_ltk);
sm_connection->sm_security_request_received = false;
sm_connection->sm_pairing_requested = false;
bool trigger_reencryption = false;
if (have_ltk){
if (trigger_pairing){
trigger_reencryption = (authenticated != 0) || (auth_required == false);
}if (trigger_pairing) { ... } else {
#ifdef ENABLE_LE_PROACTIVE_AUTHENTICATION
trigger_reencryption = true;
#else
log_info("central: defer enabling encryption for bonded device");
#endif
}else { ... }
}if (have_ltk) { ... }
if (trigger_reencryption){
log_info("central: enable encryption for bonded device");
sm_connection->sm_engine_state = SM_INITIATOR_PH4_HAS_LTK;
break;
}if (trigger_reencryption) { ... }
if (trigger_pairing){
sm_connection->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
break;
}if (trigger_pairing) { ... }
/* ... */#endif
}else { ... }
break;case ADDRESS_RESOLUTION_SUCCEEDED:
case ADDRESS_RESOLUTION_FAILED:
sm_connection->sm_irk_lookup_state = IRK_LOOKUP_FAILED;
if (IS_RESPONDER(sm_connection->sm_role)) {
#ifdef ENABLE_LE_PERIPHERAL
if (sm_connection->sm_engine_state == SM_RESPONDER_PH0_RECEIVED_LTK_W4_IRK){
sm_connection->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
}if (sm_connection->sm_engine_state == SM_RESPONDER_PH0_RECEIVED_LTK_W4_IRK) { ... }
if (sm_connection->sm_engine_state == SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED_W4_IRK){
sm_connection->sm_engine_state = SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED;
break;
}if (sm_connection->sm_engine_state == SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED_W4_IRK) { ... }
bool trigger_security_request = sm_connection->sm_pairing_requested || sm_slave_request_security;
sm_connection->sm_pairing_requested = false;
if (trigger_security_request){
sm_connection->sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST;
sm_pairing_started(sm_connection);
}if (trigger_security_request) { ... }
break;/* ... */
#endif
}if (IS_RESPONDER(sm_connection->sm_role)) { ... }
#ifdef ENABLE_LE_CENTRAL
if ((sm_connection->sm_pairing_requested == false) && (sm_connection->sm_security_request_received == false)) break;
sm_connection->sm_security_request_received = false;
sm_connection->sm_pairing_requested = false;
sm_connection->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;/* ... */
#endif
break;
case ADDRESS_RESOLUTION_FAILED:
default:
btstack_assert(false);
break;default
}switch (event) { ... }
break;case ADDRESS_RESOLUTION_FOR_CONNECTION:
default:
break;default
}switch (mode) { ... }
switch (event){
case ADDRESS_RESOLUTION_SUCCEEDED:
sm_notify_client_index(SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED, con_handle, sm_address_resolution_addr_type, sm_address_resolution_address, matched_device_id);
break;case ADDRESS_RESOLUTION_SUCCEEDED:
case ADDRESS_RESOLUTION_FAILED:
sm_notify_client_base(SM_EVENT_IDENTITY_RESOLVING_FAILED, con_handle, sm_address_resolution_addr_type, sm_address_resolution_address);
break;case ADDRESS_RESOLUTION_FAILED:
default:
btstack_assert(false);
break;default
}switch (event) { ... }
}{ ... }
static void sm_store_bonding_information(sm_connection_t * sm_conn){
int le_db_index = -1;
if ((setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION) != 0u){
int i;
for (i=0; i < le_device_db_max_count(); i++){
sm_key_t irk;
bd_addr_t address;
int address_type = BD_ADDR_TYPE_UNKNOWN;
le_device_db_info(i, &address_type, address, irk);
if (address_type == BD_ADDR_TYPE_UNKNOWN) continue;
if (memcmp(address, setup->sm_peer_address, 6) != 0) continue;
if (memcmp(irk, setup->sm_peer_irk, 16) != 0) continue;
log_info("sm: device found for IRK, updating");
le_db_index = i;
break;
}for (i=0; i < le_device_db_max_count(); i++) { ... }
}if ((setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION) != 0u) { ... } else {
memset(setup->sm_peer_irk, 0, 16);
}else { ... }
log_info("sm peer addr type %u, peer addres %s", setup->sm_peer_addr_type, bd_addr_to_str(setup->sm_peer_address));
if ((le_db_index < 0) && (setup->sm_peer_addr_type == BD_ADDR_TYPE_LE_PUBLIC)){
int i;
for (i=0; i < le_device_db_max_count(); i++){
bd_addr_t address;
int address_type = BD_ADDR_TYPE_UNKNOWN;
le_device_db_info(i, &address_type, address, NULL);
if (address_type == BD_ADDR_TYPE_UNKNOWN) continue;
log_info("device %u, sm peer addr type %u, peer addres %s", i, address_type, bd_addr_to_str(address));
if ((address_type == BD_ADDR_TYPE_LE_PUBLIC) && (memcmp(address, setup->sm_peer_address, 6) == 0)){
log_info("sm: device found for public address, updating");
le_db_index = i;
break;
}if ((address_type == BD_ADDR_TYPE_LE_PUBLIC) && (memcmp(address, setup->sm_peer_address, 6) == 0)) { ... }
}for (i=0; i < le_device_db_max_count(); i++) { ... }
}if ((le_db_index < 0) && (setup->sm_peer_addr_type == BD_ADDR_TYPE_LE_PUBLIC)) { ... }
bool new_to_le_device_db = false;
if (le_db_index < 0) {
le_db_index = le_device_db_add(setup->sm_peer_addr_type, setup->sm_peer_address, setup->sm_peer_irk);
new_to_le_device_db = true;
}if (le_db_index < 0) { ... }
if (le_db_index >= 0){
#ifdef ENABLE_LE_PRIVACY_ADDRESS_RESOLUTION
if (!new_to_le_device_db){
hci_remove_le_device_db_entry_from_resolving_list(le_db_index);
}if (!new_to_le_device_db) { ... }
hci_load_le_device_db_entry_into_resolving_list(le_db_index);/* ... */
#else
UNUSED(new_to_le_device_db);
#endif
sm_notify_client_index(SM_EVENT_IDENTITY_CREATED, sm_conn->sm_handle, setup->sm_peer_addr_type, setup->sm_peer_address, le_db_index);
sm_conn->sm_irk_lookup_state = IRK_LOOKUP_SUCCEEDED;
sm_conn->sm_le_db_index = le_db_index;
#ifdef ENABLE_LE_SIGNED_WRITE
setup->sm_le_device_index = le_db_index;
if ((setup->sm_key_distribution_sent_set) & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
log_info("sm: store local CSRK");
le_device_db_local_csrk_set(le_db_index, setup->sm_local_csrk);
le_device_db_local_counter_set(le_db_index, 0);
}if ((setup->sm_key_distribution_sent_set) & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION) { ... }
if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION){
log_info("sm: store remote CSRK");
le_device_db_remote_csrk_set(le_db_index, setup->sm_peer_csrk);
le_device_db_remote_counter_set(le_db_index, 0);
}if (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION) { ... }
/* ... */#endif
if (setup->sm_use_secure_connections){
log_info("sm: store SC LTK (key size %u, authenticated %u)", sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated);
uint8_t zero_rand[8];
memset(zero_rand, 0, 8);
le_device_db_encryption_set(le_db_index, 0, zero_rand, setup->sm_ltk, sm_conn->sm_actual_encryption_key_size,
sm_conn->sm_connection_authenticated, sm_conn->sm_connection_authorization_state == AUTHORIZATION_GRANTED, 1);
}if (setup->sm_use_secure_connections) { ... }
else if ( (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION)
&& (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION )){
log_info("sm: set encryption information (key size %u, authenticated %u)", sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated);
le_device_db_encryption_set(le_db_index, setup->sm_peer_ediv, setup->sm_peer_rand, setup->sm_peer_ltk,
sm_conn->sm_actual_encryption_key_size, sm_conn->sm_connection_authenticated, sm_conn->sm_connection_authorization_state == AUTHORIZATION_GRANTED, 0);
}else if ((setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION) && (setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION )) { ... }
}if (le_db_index >= 0) { ... }
}{ ... }
static void sm_pairing_error(sm_connection_t * sm_conn, uint8_t reason){
sm_conn->sm_pairing_failed_reason = reason;
sm_conn->sm_engine_state = SM_GENERAL_SEND_PAIRING_FAILED;
}{ ... }
static int sm_le_device_db_index_lookup(bd_addr_type_t address_type, bd_addr_t address){
int i;
for (i=0; i < le_device_db_max_count(); i++){
bd_addr_t db_address;
int db_address_type = BD_ADDR_TYPE_UNKNOWN;
le_device_db_info(i, &db_address_type, db_address, NULL);
if (address_type == BD_ADDR_TYPE_UNKNOWN) continue;
if ((address_type == (unsigned int)db_address_type) && (memcmp(address, db_address, 6) == 0)){
return i;
}if ((address_type == (unsigned int)db_address_type) && (memcmp(address, db_address, 6) == 0)) { ... }
}for (i=0; i < le_device_db_max_count(); i++) { ... }
return -1;
}{ ... }
static void sm_remove_le_device_db_entry(uint16_t i) {
le_device_db_remove(i);
#ifdef ENABLE_LE_PRIVACY_ADDRESS_RESOLUTION
gap_load_resolving_list_from_le_device_db();/* ... */
#endif
}{ ... }
static uint8_t sm_key_distribution_validate_received(sm_connection_t * sm_conn){
if ((setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION) != 0u){
int index = sm_le_device_db_index_lookup(BD_ADDR_TYPE_LE_PUBLIC, setup->sm_peer_address);
if (index >= 0){
sm_key_t irk;
le_device_db_info(index, NULL, NULL, irk);
if (memcmp(irk, setup->sm_peer_irk, 16) != 0){
log_info("New IRK for %s (type %u) does not match stored IRK -> delete bonding information", bd_addr_to_str(sm_conn->sm_peer_address), sm_conn->sm_peer_addr_type);
sm_remove_le_device_db_entry(index);
}if (memcmp(irk, setup->sm_peer_irk, 16) != 0) { ... }
}if (index >= 0) { ... }
}if ((setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION) != 0u) { ... }
return 0;
}{ ... }
static void sm_key_distribution_handle_all_received(sm_connection_t * sm_conn){
uint8_t reason = sm_key_distribution_validate_received(sm_conn);
if (reason != 0){
sm_pairing_error(sm_conn, reason);
return;
}if (reason != 0) { ... }
bool bonding_enabled = (sm_pairing_packet_get_auth_req(setup->sm_m_preq)
& sm_pairing_packet_get_auth_req(setup->sm_s_pres)
& SM_AUTHREQ_BONDING ) != 0u;
if (bonding_enabled){
sm_store_bonding_information(sm_conn);
}if (bonding_enabled) { ... } else {
log_info("Ignoring received keys, bonding not enabled");
}else { ... }
}{ ... }
static inline void sm_pdu_received_in_wrong_state(sm_connection_t * sm_conn){
sm_pairing_error(sm_conn, SM_REASON_UNSPECIFIED_REASON);
}{ ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static void sm_sc_prepare_dhkey_check(sm_connection_t * sm_conn);
static bool sm_passkey_used(stk_generation_method_t method);
static bool sm_just_works_or_numeric_comparison(stk_generation_method_t method);
static void sm_sc_start_calculating_local_confirm(sm_connection_t * sm_conn){
if (setup->sm_stk_generation_method == OOB){
sm_conn->sm_engine_state = SM_SC_W2_CMAC_FOR_CONFIRMATION;
}if (setup->sm_stk_generation_method == OOB) { ... } else {
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_nonce, 16, &sm_handle_random_result_sc_next_w2_cmac_for_confirmation, (void *)(uintptr_t) sm_conn->sm_handle);
}else { ... }
}sm_sc_start_calculating_local_confirm (sm_connection_t * sm_conn) { ... }
static void sm_sc_state_after_receiving_random(sm_connection_t * sm_conn){
if (IS_RESPONDER(sm_conn->sm_role)){
if (setup->sm_stk_generation_method == OOB){
log_info("Generate Nb");
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_nonce, 16, &sm_handle_random_result_sc_next_send_pairing_random, (void *)(uintptr_t) sm_conn->sm_handle);
}if (setup->sm_stk_generation_method == OOB) { ... } else {
sm_conn->sm_engine_state = SM_SC_SEND_PAIRING_RANDOM;
}else { ... }
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
switch (setup->sm_stk_generation_method){
case JUST_WORKS:
sm_sc_prepare_dhkey_check(sm_conn);
break;
case JUST_WORKS:
case NUMERIC_COMPARISON:
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_G2;
break;case NUMERIC_COMPARISON:
case PK_INIT_INPUT:
case PK_RESP_INPUT:
case PK_BOTH_INPUT:
if (setup->sm_passkey_bit < 20u) {
sm_sc_start_calculating_local_confirm(sm_conn);
}if (setup->sm_passkey_bit < 20u) { ... } else {
sm_sc_prepare_dhkey_check(sm_conn);
}else { ... }
break;case PK_BOTH_INPUT:
case OOB:
sm_sc_prepare_dhkey_check(sm_conn);
break;case OOB:
default:
btstack_assert(false);
break;default
}switch (setup->sm_stk_generation_method) { ... }
}else { ... }
}sm_sc_state_after_receiving_random (sm_connection_t * sm_conn) { ... }
static void sm_sc_cmac_done(uint8_t * hash){
log_info("sm_sc_cmac_done: ");
log_info_hexdump(hash, 16);
if (sm_sc_oob_state == SM_SC_OOB_W4_CONFIRM){
sm_sc_oob_state = SM_SC_OOB_IDLE;
(*sm_sc_oob_callback)(hash, sm_sc_oob_random);
return;
}if (sm_sc_oob_state == SM_SC_OOB_W4_CONFIRM) { ... }
sm_connection_t * sm_conn = sm_cmac_connection;
sm_cmac_connection = NULL;
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
link_key_type_t link_key_type;
#endif
switch (sm_conn->sm_engine_state){
case SM_SC_W4_CMAC_FOR_CONFIRMATION:
(void)memcpy(setup->sm_local_confirm, hash, 16);
sm_conn->sm_engine_state = SM_SC_SEND_CONFIRMATION;
break;case SM_SC_W4_CMAC_FOR_CONFIRMATION:
case SM_SC_W4_CMAC_FOR_CHECK_CONFIRMATION:
if (0 != memcmp(hash, setup->sm_peer_confirm, 16)){
sm_pairing_error(sm_conn, SM_REASON_CONFIRM_VALUE_FAILED);
break;
}if (0 != memcmp(hash, setup->sm_peer_confirm, 16)) { ... }
sm_sc_state_after_receiving_random(sm_conn);
break;case SM_SC_W4_CMAC_FOR_CHECK_CONFIRMATION:
case SM_SC_W4_CALCULATE_G2: {
uint32_t vab = big_endian_read_32(hash, 12) % 1000000;
big_endian_store_32(setup->sm_tk, 12, vab);
sm_conn->sm_engine_state = SM_SC_W4_USER_RESPONSE;
sm_trigger_user_response(sm_conn);
break;
...}case SM_SC_W4_CALCULATE_G2:
case SM_SC_W4_CALCULATE_F5_SALT:
(void)memcpy(setup->sm_t, hash, 16);
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F5_MACKEY;
break;case SM_SC_W4_CALCULATE_F5_SALT:
case SM_SC_W4_CALCULATE_F5_MACKEY:
(void)memcpy(setup->sm_mackey, hash, 16);
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F5_LTK;
break;case SM_SC_W4_CALCULATE_F5_MACKEY:
case SM_SC_W4_CALCULATE_F5_LTK:
(void)memcpy(setup->sm_ltk, hash, 16);
(void)memcpy(setup->sm_local_ltk, hash, 16);
sm_truncate_key(setup->sm_ltk, sm_conn->sm_actual_encryption_key_size);
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK;
break;case SM_SC_W4_CALCULATE_F5_LTK:
case SM_SC_W4_CALCULATE_F6_FOR_DHKEY_CHECK:
(void)memcpy(setup->sm_local_dhkey_check, hash, 16);
if (IS_RESPONDER(sm_conn->sm_role)){
if ((setup->sm_state_vars & SM_STATE_VAR_DHKEY_COMMAND_RECEIVED) != 0u){
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK;
}if ((setup->sm_state_vars & SM_STATE_VAR_DHKEY_COMMAND_RECEIVED) != 0u) { ... } else {
sm_conn->sm_engine_state = SM_SC_W4_DHKEY_CHECK_COMMAND;
}else { ... }
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
sm_conn->sm_engine_state = SM_SC_SEND_DHKEY_CHECK_COMMAND;
}else { ... }
break;case SM_SC_W4_CALCULATE_F6_FOR_DHKEY_CHECK:
case SM_SC_W4_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK:
if (0 != memcmp(hash, setup->sm_peer_dhkey_check, 16) ){
sm_pairing_error(sm_conn, SM_REASON_DHKEY_CHECK_FAILED);
break;
}if (0 != memcmp(hash, setup->sm_peer_dhkey_check, 16)) { ... }
if (IS_RESPONDER(sm_conn->sm_role)){
sm_conn->sm_engine_state = SM_SC_SEND_DHKEY_CHECK_COMMAND;
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
sm_conn->sm_engine_state = SM_INITIATOR_PH3_SEND_START_ENCRYPTION;
}else { ... }
break;
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATIONcase SM_SC_W4_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK:
case SM_SC_W4_CALCULATE_ILK:
(void)memcpy(setup->sm_t, hash, 16);
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_BR_EDR_LINK_KEY;
break;case SM_SC_W4_CALCULATE_ILK:
case SM_SC_W4_CALCULATE_BR_EDR_LINK_KEY:
reverse_128(hash, setup->sm_t);
link_key_type = sm_conn->sm_connection_authenticated ?
AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256 : UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256;
log_info("Derived classic link key from LE using h6, type %u", (int) link_key_type);
gap_store_link_key_for_bd_addr(setup->sm_peer_address, setup->sm_t, link_key_type);
if (IS_RESPONDER(sm_conn->sm_role)){
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
}else { ... }
sm_pairing_complete(sm_conn, ERROR_CODE_SUCCESS, 0);
sm_done_for_handle(sm_conn->sm_handle);
break;case SM_SC_W4_CALCULATE_BR_EDR_LINK_KEY:
case SM_BR_EDR_W4_CALCULATE_ILK:
(void)memcpy(setup->sm_t, hash, 16);
sm_conn->sm_engine_state = SM_BR_EDR_W2_CALCULATE_LE_LTK;
break;case SM_BR_EDR_W4_CALCULATE_ILK:
case SM_BR_EDR_W4_CALCULATE_LE_LTK:
log_info("Derived LE LTK from BR/EDR Link Key");
log_info_key("Link Key", hash);
(void)memcpy(setup->sm_ltk, hash, 16);
sm_truncate_key(setup->sm_ltk, sm_conn->sm_actual_encryption_key_size);
sm_conn->sm_connection_authenticated = setup->sm_link_key_type == AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256;
sm_store_bonding_information(sm_conn);
sm_done_for_handle(sm_conn->sm_handle);
break;/* ... */
#endif
default:
log_error("sm_sc_cmac_done in state %u", sm_conn->sm_engine_state);
break;default
}switch (sm_conn->sm_engine_state) { ... }
sm_trigger_run();
}sm_sc_cmac_done (uint8_t * hash) { ... }
static void f4_engine(sm_connection_t * sm_conn, const sm_key256_t u, const sm_key256_t v, const sm_key_t x, uint8_t z){
const uint16_t message_len = 65;
sm_cmac_connection = sm_conn;
(void)memcpy(sm_cmac_sc_buffer, u, 32);
(void)memcpy(sm_cmac_sc_buffer + 32, v, 32);
sm_cmac_sc_buffer[64] = z;
log_info("f4 key");
log_info_hexdump(x, 16);
log_info("f4 message");
log_info_hexdump(sm_cmac_sc_buffer, message_len);
sm_cmac_message_start(x, message_len, sm_cmac_sc_buffer, &sm_sc_cmac_done);
}f4_engine (sm_connection_t * sm_conn, const sm_key256_t u, const sm_key256_t v, const sm_key_t x, uint8_t z) { ... }
static const uint8_t f5_key_id[] = { 0x62, 0x74, 0x6c, 0x65 };
static const uint8_t f5_length[] = { 0x01, 0x00};
static void f5_calculate_salt(sm_connection_t * sm_conn){
static const sm_key_t f5_salt = { 0x6C ,0x88, 0x83, 0x91, 0xAA, 0xF5, 0xA5, 0x38, 0x60, 0x37, 0x0B, 0xDB, 0x5A, 0x60, 0x83, 0xBE};
log_info("f5_calculate_salt");
const uint16_t message_len = 32;
sm_cmac_connection = sm_conn;
(void)memcpy(sm_cmac_sc_buffer, setup->sm_dhkey, message_len);
sm_cmac_message_start(f5_salt, message_len, sm_cmac_sc_buffer, &sm_sc_cmac_done);
}f5_calculate_salt (sm_connection_t * sm_conn) { ... }
static inline void f5_mackkey(sm_connection_t * sm_conn, sm_key_t t, const sm_key_t n1, const sm_key_t n2, const sm_key56_t a1, const sm_key56_t a2){
const uint16_t message_len = 53;
sm_cmac_connection = sm_conn;
sm_cmac_sc_buffer[0] = 0;
(void)memcpy(sm_cmac_sc_buffer + 01, f5_key_id, 4);
(void)memcpy(sm_cmac_sc_buffer + 05, n1, 16);
(void)memcpy(sm_cmac_sc_buffer + 21, n2, 16);
(void)memcpy(sm_cmac_sc_buffer + 37, a1, 7);
(void)memcpy(sm_cmac_sc_buffer + 44, a2, 7);
(void)memcpy(sm_cmac_sc_buffer + 51, f5_length, 2);
log_info("f5 key");
log_info_hexdump(t, 16);
log_info("f5 message for MacKey");
log_info_hexdump(sm_cmac_sc_buffer, message_len);
sm_cmac_message_start(t, message_len, sm_cmac_sc_buffer, &sm_sc_cmac_done);
}f5_mackkey (sm_connection_t * sm_conn, sm_key_t t, const sm_key_t n1, const sm_key_t n2, const sm_key56_t a1, const sm_key56_t a2) { ... }
static void f5_calculate_mackey(sm_connection_t * sm_conn){
sm_key56_t bd_addr_master, bd_addr_slave;
bd_addr_master[0] = setup->sm_m_addr_type;
bd_addr_slave[0] = setup->sm_s_addr_type;
(void)memcpy(&bd_addr_master[1], setup->sm_m_address, 6);
(void)memcpy(&bd_addr_slave[1], setup->sm_s_address, 6);
if (IS_RESPONDER(sm_conn->sm_role)){
f5_mackkey(sm_conn, setup->sm_t, setup->sm_peer_nonce, setup->sm_local_nonce, bd_addr_master, bd_addr_slave);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
f5_mackkey(sm_conn, setup->sm_t, setup->sm_local_nonce, setup->sm_peer_nonce, bd_addr_master, bd_addr_slave);
}else { ... }
}f5_calculate_mackey (sm_connection_t * sm_conn) { ... }
static inline void f5_ltk(sm_connection_t * sm_conn, sm_key_t t){
const uint16_t message_len = 53;
sm_cmac_connection = sm_conn;
sm_cmac_sc_buffer[0] = 1;
log_info("f5 key");
log_info_hexdump(t, 16);
log_info("f5 message for LTK");
log_info_hexdump(sm_cmac_sc_buffer, message_len);
sm_cmac_message_start(t, message_len, sm_cmac_sc_buffer, &sm_sc_cmac_done);
}f5_ltk (sm_connection_t * sm_conn, sm_key_t t) { ... }
static void f5_calculate_ltk(sm_connection_t * sm_conn){
f5_ltk(sm_conn, setup->sm_t);
}f5_calculate_ltk (sm_connection_t * sm_conn) { ... }
static void f6_setup(const sm_key_t n1, const sm_key_t n2, const sm_key_t r, const sm_key24_t io_cap, const sm_key56_t a1, const sm_key56_t a2){
(void)memcpy(sm_cmac_sc_buffer, n1, 16);
(void)memcpy(sm_cmac_sc_buffer + 16, n2, 16);
(void)memcpy(sm_cmac_sc_buffer + 32, r, 16);
(void)memcpy(sm_cmac_sc_buffer + 48, io_cap, 3);
(void)memcpy(sm_cmac_sc_buffer + 51, a1, 7);
(void)memcpy(sm_cmac_sc_buffer + 58, a2, 7);
}f6_setup (const sm_key_t n1, const sm_key_t n2, const sm_key_t r, const sm_key24_t io_cap, const sm_key56_t a1, const sm_key56_t a2) { ... }
static void f6_engine(sm_connection_t * sm_conn, const sm_key_t w){
const uint16_t message_len = 65;
sm_cmac_connection = sm_conn;
log_info("f6 key");
log_info_hexdump(w, 16);
log_info("f6 message");
log_info_hexdump(sm_cmac_sc_buffer, message_len);
sm_cmac_message_start(w, 65, sm_cmac_sc_buffer, &sm_sc_cmac_done);
}f6_engine (sm_connection_t * sm_conn, const sm_key_t w) { ... }
static void g2_engine(sm_connection_t * sm_conn, const sm_key256_t u, const sm_key256_t v, const sm_key_t x, const sm_key_t y){
const uint16_t message_len = 80;
sm_cmac_connection = sm_conn;
(void)memcpy(sm_cmac_sc_buffer, u, 32);
(void)memcpy(sm_cmac_sc_buffer + 32, v, 32);
(void)memcpy(sm_cmac_sc_buffer + 64, y, 16);
log_info("g2 key");
log_info_hexdump(x, 16);
log_info("g2 message");
log_info_hexdump(sm_cmac_sc_buffer, message_len);
sm_cmac_message_start(x, message_len, sm_cmac_sc_buffer, &sm_sc_cmac_done);
}g2_engine (sm_connection_t * sm_conn, const sm_key256_t u, const sm_key256_t v, const sm_key_t x, const sm_key_t y) { ... }
static void g2_calculate(sm_connection_t * sm_conn) {
if (IS_RESPONDER(sm_conn->sm_role)){
g2_engine(sm_conn, setup->sm_peer_q, ec_q, setup->sm_peer_nonce, setup->sm_local_nonce);;
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
g2_engine(sm_conn, ec_q, setup->sm_peer_q, setup->sm_local_nonce, setup->sm_peer_nonce);
}else { ... }
}g2_calculate (sm_connection_t * sm_conn) { ... }
static void sm_sc_calculate_local_confirm(sm_connection_t * sm_conn){
uint8_t z = 0;
if (sm_passkey_entry(setup->sm_stk_generation_method)){
uint32_t pk = big_endian_read_32(setup->sm_tk, 12);
z = 0x80u | ((pk >> setup->sm_passkey_bit) & 1u);
setup->sm_passkey_bit++;
}if (sm_passkey_entry(setup->sm_stk_generation_method)) { ... }
f4_engine(sm_conn, ec_q, setup->sm_peer_q, setup->sm_local_nonce, z);
}sm_sc_calculate_local_confirm (sm_connection_t * sm_conn) { ... }
static void sm_sc_calculate_remote_confirm(sm_connection_t * sm_conn){
if (setup->sm_stk_generation_method == OOB){
if (IS_RESPONDER(sm_conn->sm_role)){
f4_engine(sm_conn, setup->sm_peer_q, setup->sm_peer_q, setup->sm_ra, 0);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
f4_engine(sm_conn, setup->sm_peer_q, setup->sm_peer_q, setup->sm_rb, 0);
}else { ... }
return;
}if (setup->sm_stk_generation_method == OOB) { ... }
uint8_t z = 0;
if (sm_passkey_entry(setup->sm_stk_generation_method)){
uint32_t pk = big_endian_read_32(setup->sm_tk, 12);
z = 0x80u | ((pk >> (setup->sm_passkey_bit-1u)) & 1u);
}if (sm_passkey_entry(setup->sm_stk_generation_method)) { ... }
f4_engine(sm_conn, setup->sm_peer_q, ec_q, setup->sm_peer_nonce, z);
}sm_sc_calculate_remote_confirm (sm_connection_t * sm_conn) { ... }
static void sm_sc_prepare_dhkey_check(sm_connection_t * sm_conn){
log_info("sm_sc_prepare_dhkey_check, DHKEY calculated %u", (setup->sm_state_vars & SM_STATE_VAR_DHKEY_CALCULATED) != 0 ? 1 : 0);
if ((setup->sm_state_vars & SM_STATE_VAR_DHKEY_CALCULATED) != 0u){
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F5_SALT;
}if ((setup->sm_state_vars & SM_STATE_VAR_DHKEY_CALCULATED) != 0u) { ... } else {
sm_conn->sm_engine_state = SM_SC_W4_CALCULATE_DHKEY;
}else { ... }
}sm_sc_prepare_dhkey_check (sm_connection_t * sm_conn) { ... }
static void sm_sc_dhkey_calculated(void * arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (sm_conn == NULL) return;
if (sm_is_ff(setup->sm_dhkey, 32)){
log_info("sm: peer public key invalid");
sm_pairing_error(sm_conn, SM_REASON_DHKEY_CHECK_FAILED);
return;
}if (sm_is_ff(setup->sm_dhkey, 32)) { ... }
log_info("dhkey");
log_info_hexdump(&setup->sm_dhkey[0], 32);
setup->sm_state_vars |= SM_STATE_VAR_DHKEY_CALCULATED;
if (sm_conn->sm_engine_state == SM_SC_W4_CALCULATE_DHKEY){
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F5_SALT;
}if (sm_conn->sm_engine_state == SM_SC_W4_CALCULATE_DHKEY) { ... }
sm_trigger_run();
}sm_sc_dhkey_calculated (void * arg) { ... }
static void sm_sc_calculate_f6_for_dhkey_check(sm_connection_t * sm_conn){
sm_key56_t bd_addr_master, bd_addr_slave;
bd_addr_master[0] = setup->sm_m_addr_type;
bd_addr_slave[0] = setup->sm_s_addr_type;
(void)memcpy(&bd_addr_master[1], setup->sm_m_address, 6);
(void)memcpy(&bd_addr_slave[1], setup->sm_s_address, 6);
uint8_t iocap_a[3];
iocap_a[0] = sm_pairing_packet_get_auth_req(setup->sm_m_preq);
iocap_a[1] = sm_pairing_packet_get_oob_data_flag(setup->sm_m_preq);
iocap_a[2] = sm_pairing_packet_get_io_capability(setup->sm_m_preq);
uint8_t iocap_b[3];
iocap_b[0] = sm_pairing_packet_get_auth_req(setup->sm_s_pres);
iocap_b[1] = sm_pairing_packet_get_oob_data_flag(setup->sm_s_pres);
iocap_b[2] = sm_pairing_packet_get_io_capability(setup->sm_s_pres);
if (IS_RESPONDER(sm_conn->sm_role)){
f6_setup(setup->sm_local_nonce, setup->sm_peer_nonce, setup->sm_ra, iocap_b, bd_addr_slave, bd_addr_master);
f6_engine(sm_conn, setup->sm_mackey);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
f6_setup( setup->sm_local_nonce, setup->sm_peer_nonce, setup->sm_rb, iocap_a, bd_addr_master, bd_addr_slave);
f6_engine(sm_conn, setup->sm_mackey);
}else { ... }
}sm_sc_calculate_f6_for_dhkey_check (sm_connection_t * sm_conn) { ... }
static void sm_sc_calculate_f6_to_verify_dhkey_check(sm_connection_t * sm_conn){
sm_key56_t bd_addr_master, bd_addr_slave;
bd_addr_master[0] = setup->sm_m_addr_type;
bd_addr_slave[0] = setup->sm_s_addr_type;
(void)memcpy(&bd_addr_master[1], setup->sm_m_address, 6);
(void)memcpy(&bd_addr_slave[1], setup->sm_s_address, 6);
uint8_t iocap_a[3];
iocap_a[0] = sm_pairing_packet_get_auth_req(setup->sm_m_preq);
iocap_a[1] = sm_pairing_packet_get_oob_data_flag(setup->sm_m_preq);
iocap_a[2] = sm_pairing_packet_get_io_capability(setup->sm_m_preq);
uint8_t iocap_b[3];
iocap_b[0] = sm_pairing_packet_get_auth_req(setup->sm_s_pres);
iocap_b[1] = sm_pairing_packet_get_oob_data_flag(setup->sm_s_pres);
iocap_b[2] = sm_pairing_packet_get_io_capability(setup->sm_s_pres);
if (IS_RESPONDER(sm_conn->sm_role)){
f6_setup(setup->sm_peer_nonce, setup->sm_local_nonce, setup->sm_rb, iocap_a, bd_addr_master, bd_addr_slave);
f6_engine(sm_conn, setup->sm_mackey);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
f6_setup(setup->sm_peer_nonce, setup->sm_local_nonce, setup->sm_ra, iocap_b, bd_addr_slave, bd_addr_master);
f6_engine(sm_conn, setup->sm_mackey);
}else { ... }
}sm_sc_calculate_f6_to_verify_dhkey_check (sm_connection_t * sm_conn) { ... }
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
static void h6_engine(sm_connection_t * sm_conn, const sm_key_t w, const uint32_t key_id){
const uint16_t message_len = 4;
sm_cmac_connection = sm_conn;
big_endian_store_32(sm_cmac_sc_buffer, 0, key_id);
log_info("h6 key");
log_info_hexdump(w, 16);
log_info("h6 message");
log_info_hexdump(sm_cmac_sc_buffer, message_len);
sm_cmac_message_start(w, message_len, sm_cmac_sc_buffer, &sm_sc_cmac_done);
}h6_engine (sm_connection_t * sm_conn, const sm_key_t w, const uint32_t key_id) { ... }
static void h7_engine(sm_connection_t * sm_conn, const sm_key_t salt, const sm_key_t w) {
const uint16_t message_len = 16;
sm_cmac_connection = sm_conn;
log_info("h7 key");
log_info_hexdump(salt, 16);
log_info("h7 message");
log_info_hexdump(w, 16);
sm_cmac_message_start(salt, message_len, w, &sm_sc_cmac_done);
}h7_engine (sm_connection_t * sm_conn, const sm_key_t salt, const sm_key_t w) { ... }
static void h6_calculate_ilk_from_le_ltk(sm_connection_t * sm_conn){
h6_engine(sm_conn, setup->sm_local_ltk, 0x746D7031);
}h6_calculate_ilk_from_le_ltk (sm_connection_t * sm_conn) { ... }
static void h6_calculate_ilk_from_br_edr(sm_connection_t * sm_conn){
h6_engine(sm_conn, setup->sm_link_key, 0x746D7032);
}h6_calculate_ilk_from_br_edr (sm_connection_t * sm_conn) { ... }
static void h6_calculate_br_edr_link_key(sm_connection_t * sm_conn){
h6_engine(sm_conn, setup->sm_t, 0x6c656272);
}h6_calculate_br_edr_link_key (sm_connection_t * sm_conn) { ... }
static void h6_calculate_le_ltk(sm_connection_t * sm_conn){
h6_engine(sm_conn, setup->sm_t, 0x62726C65);
}h6_calculate_le_ltk (sm_connection_t * sm_conn) { ... }
static void h7_calculate_ilk_from_le_ltk(sm_connection_t * sm_conn){
const uint8_t salt[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31};
h7_engine(sm_conn, salt, setup->sm_local_ltk);
}h7_calculate_ilk_from_le_ltk (sm_connection_t * sm_conn) { ... }
static void h7_calculate_ilk_from_br_edr(sm_connection_t * sm_conn){
const uint8_t salt[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x32};
h7_engine(sm_conn, salt, setup->sm_link_key);
}h7_calculate_ilk_from_br_edr (sm_connection_t * sm_conn) { ... }
static void sm_ctkd_fetch_br_edr_link_key(sm_connection_t * sm_conn){
hci_connection_t * hci_connection = hci_connection_for_handle(sm_conn->sm_handle);
btstack_assert(hci_connection != NULL);
reverse_128(hci_connection->link_key, setup->sm_link_key);
setup->sm_link_key_type = hci_connection->link_key_type;
}sm_ctkd_fetch_br_edr_link_key (sm_connection_t * sm_conn) { ... }
static void sm_ctkd_start_from_br_edr(sm_connection_t * sm_conn){
bool derive_ltk = (sm_pairing_packet_get_initiator_key_distribution(setup->sm_s_pres) &
sm_pairing_packet_get_responder_key_distribution(setup->sm_s_pres) & SM_KEYDIST_ENC_KEY) != 0;
if (derive_ltk){
bool use_h7 = (sm_pairing_packet_get_auth_req(setup->sm_m_preq) & sm_pairing_packet_get_auth_req(setup->sm_s_pres) & SM_AUTHREQ_CT2) != 0;
sm_conn->sm_engine_state = use_h7 ? SM_BR_EDR_W2_CALCULATE_ILK_USING_H7 : SM_BR_EDR_W2_CALCULATE_ILK_USING_H6;
}if (derive_ltk) { ... } else {
sm_done_for_handle(sm_conn->sm_handle);
}else { ... }
}sm_ctkd_start_from_br_edr (sm_connection_t * sm_conn) { ... }
/* ... */
#endif
/* ... */
#endif
#if defined(ENABLE_LE_SECURE_CONNECTIONS) || defined(ENABLE_LE_CENTRAL)
static void sm_load_security_info(sm_connection_t * sm_connection){
int encryption_key_size;
int authenticated;
int authorized;
int secure_connection;
le_device_db_encryption_get(sm_connection->sm_le_db_index, &setup->sm_peer_ediv, setup->sm_peer_rand, setup->sm_peer_ltk,
&encryption_key_size, &authenticated, &authorized, &secure_connection);
log_info("db index %u, key size %u, authenticated %u, authorized %u, secure connetion %u", sm_connection->sm_le_db_index, encryption_key_size, authenticated, authorized, secure_connection);
sm_connection->sm_actual_encryption_key_size = encryption_key_size;
sm_connection->sm_connection_authenticated = authenticated;
sm_connection->sm_connection_authorization_state = authorized ? AUTHORIZATION_GRANTED : AUTHORIZATION_UNKNOWN;
sm_connection->sm_connection_sc = secure_connection != 0;
}sm_load_security_info (sm_connection_t * sm_connection) { ... }
/* ... */#endif
#ifdef ENABLE_LE_PERIPHERAL
static void sm_start_calculating_ltk_from_ediv_and_rand(sm_connection_t * sm_connection){
(void)memcpy(setup->sm_local_rand, sm_connection->sm_local_rand, 8);
setup->sm_local_ediv = sm_connection->sm_local_ediv;
sm_connection->sm_actual_encryption_key_size = (setup->sm_local_rand[7u] & 0x0fu) + 1u;
sm_connection->sm_connection_authenticated = (setup->sm_local_rand[7u] & 0x10u) >> 4u;
sm_connection->sm_connection_sc = false;
log_info("sm: received ltk request with key size %u, authenticated %u",
sm_connection->sm_actual_encryption_key_size, sm_connection->sm_connection_authenticated);
}{ ... }
/* ... */#endif
static bool sm_run_dpkg(void){
switch (dkg_state){
case DKG_CALC_IRK:
if (sm_aes128_state == SM_AES128_IDLE) {
log_info("DKG_CALC_IRK started");
sm_d1_d_prime(1, 0, sm_aes128_plaintext);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_persistent_ir, sm_aes128_plaintext, sm_persistent_irk, sm_handle_encryption_result_dkg_irk, NULL);
return true;
}if (sm_aes128_state == SM_AES128_IDLE) { ... }
break;case DKG_CALC_IRK:
case DKG_CALC_DHK:
if (sm_aes128_state == SM_AES128_IDLE) {
log_info("DKG_CALC_DHK started");
sm_d1_d_prime(3, 0, sm_aes128_plaintext);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_persistent_ir, sm_aes128_plaintext, sm_persistent_dhk, sm_handle_encryption_result_dkg_dhk, NULL);
return true;
}if (sm_aes128_state == SM_AES128_IDLE) { ... }
break;case DKG_CALC_DHK:
default:
break;default
}switch (dkg_state) { ... }
return false;
}{ ... }
static bool sm_run_rau(void){
switch (rau_state){
case RAU_GET_RANDOM:
rau_state = RAU_W4_RANDOM;
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_address, 6, &sm_handle_random_result_rau, NULL);
return true;case RAU_GET_RANDOM:
case RAU_GET_ENC:
if (sm_aes128_state == SM_AES128_IDLE) {
sm_ah_r_prime(sm_random_address, sm_aes128_plaintext);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_persistent_irk, sm_aes128_plaintext, sm_aes128_ciphertext, sm_handle_encryption_result_rau, NULL);
return true;
}if (sm_aes128_state == SM_AES128_IDLE) { ... }
break;case RAU_GET_ENC:
default:
break;default
}switch (rau_state) { ... }
return false;
}{ ... }
static bool sm_run_irk_lookup(void){
btstack_linked_list_iterator_t it;
if (sm_address_resolution_idle()){
hci_connections_get_iterator(&it);
while(btstack_linked_list_iterator_has_next(&it)){
hci_connection_t * hci_connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
sm_connection_t * sm_connection = &hci_connection->sm_connection;
if (sm_connection->sm_irk_lookup_state == IRK_LOOKUP_W4_READY){
sm_address_resolution_start_lookup(sm_connection->sm_peer_addr_type, sm_connection->sm_handle, sm_connection->sm_peer_address, ADDRESS_RESOLUTION_FOR_CONNECTION, sm_connection);
sm_connection->sm_irk_lookup_state = IRK_LOOKUP_STARTED;
break;
}if (sm_connection->sm_irk_lookup_state == IRK_LOOKUP_W4_READY) { ... }
}while (btstack_linked_list_iterator_has_next(&it)) { ... }
}if (sm_address_resolution_idle()) { ... }
if (sm_address_resolution_idle()) {
if (!btstack_linked_list_empty(&sm_address_resolution_general_queue)){
sm_lookup_entry_t * entry = (sm_lookup_entry_t *) sm_address_resolution_general_queue;
btstack_linked_list_remove(&sm_address_resolution_general_queue, (btstack_linked_item_t *) entry);
sm_address_resolution_start_lookup(entry->address_type, 0, entry->address, ADDRESS_RESOLUTION_GENERAL, NULL);
btstack_memory_sm_lookup_entry_free(entry);
}if (!btstack_linked_list_empty(&sm_address_resolution_general_queue)) { ... }
}if (sm_address_resolution_idle()) { ... }
if (!sm_address_resolution_idle()){
bool started_aes128 = false;
while (sm_address_resolution_test < le_device_db_max_count()){
int addr_type = BD_ADDR_TYPE_UNKNOWN;
bd_addr_t addr;
sm_key_t irk;
le_device_db_info(sm_address_resolution_test, &addr_type, addr, irk);
if (addr_type == BD_ADDR_TYPE_UNKNOWN){
sm_address_resolution_test++;
continue;
}if (addr_type == BD_ADDR_TYPE_UNKNOWN) { ... }
log_info("LE Device Lookup: device %u of %u - type %u, %s", sm_address_resolution_test,
le_device_db_max_count(), addr_type, bd_addr_to_str(addr));
int regular_addr_type = sm_address_resolution_addr_type & 1;
if ((regular_addr_type == addr_type) && (memcmp(addr, sm_address_resolution_address, 6) == 0)){
log_info("LE Device Lookup: found by { addr_type, address} ");
sm_address_resolution_handle_event(ADDRESS_RESOLUTION_SUCCEEDED);
break;
}if ((regular_addr_type == addr_type) && (memcmp(addr, sm_address_resolution_address, 6) == 0)) { ... }
if (sm_address_resolution_addr_type != BD_ADDR_TYPE_LE_RANDOM){
sm_address_resolution_test++;
continue;
}if (sm_address_resolution_addr_type != BD_ADDR_TYPE_LE_RANDOM) { ... }
if (sm_is_null_key(irk)){
sm_address_resolution_test++;
continue;
}if (sm_is_null_key(irk)) { ... }
if (sm_aes128_state == SM_AES128_ACTIVE) break;
log_info("LE Device Lookup: calculate AH");
log_info_key("IRK", irk);
(void)memcpy(sm_aes128_key, irk, 16);
sm_ah_r_prime(sm_address_resolution_address, sm_aes128_plaintext);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_aes128_key, sm_aes128_plaintext, sm_aes128_ciphertext, sm_handle_encryption_result_address_resolution, NULL);
started_aes128 = true;
break;
}while (sm_address_resolution_test < le_device_db_max_count()) { ... }
if (started_aes128){
return true;
}if (started_aes128) { ... }
if (sm_address_resolution_test >= le_device_db_max_count()){
log_info("LE Device Lookup: not found");
sm_address_resolution_handle_event(ADDRESS_RESOLUTION_FAILED);
}if (sm_address_resolution_test >= le_device_db_max_count()) { ... }
}if (!sm_address_resolution_idle()) { ... }
return false;
}{ ... }
static bool sm_run_oob(void){
#ifdef ENABLE_LE_SECURE_CONNECTIONS
switch (sm_sc_oob_state){
case SM_SC_OOB_W2_CALC_CONFIRM:
if (!sm_cmac_ready()) break;
sm_sc_oob_state = SM_SC_OOB_W4_CONFIRM;
f4_engine(NULL, ec_q, ec_q, sm_sc_oob_random, 0);
return true;case SM_SC_OOB_W2_CALC_CONFIRM:
default:
break;default
}switch (sm_sc_oob_state) { ... }
/* ... */#endif
return false;
}{ ... }
static void sm_send_connectionless(sm_connection_t * sm_connection, const uint8_t * buffer, uint16_t size){
l2cap_send_connectionless(sm_connection->sm_handle, sm_connection->sm_cid, (uint8_t*) buffer, size);
}{ ... }
static bool sm_run_basic(void){
btstack_linked_list_iterator_t it;
hci_connections_get_iterator(&it);
while(btstack_linked_list_iterator_has_next(&it)){
hci_connection_t * hci_connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
sm_connection_t * sm_connection = &hci_connection->sm_connection;
switch(sm_connection->sm_engine_state){
case SM_GENERAL_SEND_PAIRING_FAILED: {
uint8_t buffer[2];
buffer[0] = SM_CODE_PAIRING_FAILED;
buffer[1] = sm_connection->sm_pairing_failed_reason;
sm_connection->sm_engine_state = sm_connection->sm_role ? SM_RESPONDER_IDLE : SM_INITIATOR_CONNECTED;
sm_send_connectionless(sm_connection, (uint8_t*) buffer, sizeof(buffer));
sm_pairing_complete(sm_connection, ERROR_CODE_AUTHENTICATION_FAILURE, sm_connection->sm_pairing_failed_reason);
sm_done_for_handle(sm_connection->sm_handle);
break;
...}
case SM_GENERAL_SEND_PAIRING_FAILED:
case SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY:
sm_connection->sm_engine_state = SM_RESPONDER_IDLE;
hci_send_cmd(&hci_le_long_term_key_negative_reply, sm_connection->sm_handle);
return true;
#ifdef ENABLE_LE_SECURE_CONNECTIONScase SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY:
case SM_SC_RECEIVED_LTK_REQUEST:
switch (sm_connection->sm_irk_lookup_state){
case IRK_LOOKUP_FAILED:
log_info("LTK Request: IRK Lookup Failed)");
sm_connection->sm_engine_state = SM_RESPONDER_IDLE;
hci_send_cmd(&hci_le_long_term_key_negative_reply, sm_connection->sm_handle);
return true;case IRK_LOOKUP_FAILED:
default:
break;default
}switch (sm_connection->sm_irk_lookup_state) { ... }
break;/* ... */
#endifcase SM_SC_RECEIVED_LTK_REQUEST:
default:
break;default
}switch (sm_connection->sm_engine_state) { ... }
}while (btstack_linked_list_iterator_has_next(&it)) { ... }
return false;
}{ ... }
static void sm_run_activate_connection(void){
btstack_linked_list_iterator_t it;
hci_connections_get_iterator(&it);
while((sm_active_connection_handle == HCI_CON_HANDLE_INVALID) && btstack_linked_list_iterator_has_next(&it)){
hci_connection_t * hci_connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
sm_connection_t * sm_connection = &hci_connection->sm_connection;
bool done = true;
int err;
UNUSED(err);
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if ( (sm_connection->sm_engine_state == SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED)
|| (sm_connection->sm_engine_state == SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST)
|| (sm_connection->sm_engine_state == SM_RESPONDER_SEND_SECURITY_REQUEST)){
if (ec_key_generation_state == EC_KEY_GENERATION_IDLE){
sm_ec_generate_new_key();
}if (ec_key_generation_state == EC_KEY_GENERATION_IDLE) { ... }
if (ec_key_generation_state != EC_KEY_GENERATION_DONE){
continue;
}if (ec_key_generation_state != EC_KEY_GENERATION_DONE) { ... }
}if ((sm_connection->sm_engine_state == SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED) || (sm_connection->sm_engine_state == SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST) || (sm_connection->sm_engine_state == SM_RESPONDER_SEND_SECURITY_REQUEST)) { ... }
/* ... */#endif
switch (sm_connection->sm_engine_state) {
#ifdef ENABLE_LE_PERIPHERAL
case SM_RESPONDER_SEND_SECURITY_REQUEST:
case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED:
case SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST:
#ifdef ENABLE_LE_SECURE_CONNECTIONScase SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST:
case SM_SC_RECEIVED_LTK_REQUEST:
#endif/* ... */
#endif
#ifdef ENABLE_LE_CENTRAL
case SM_INITIATOR_PH4_HAS_LTK:
case SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST:/* ... */
#endif
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
case SM_BR_EDR_RESPONDER_PAIRING_REQUEST_RECEIVED:
case SM_BR_EDR_INITIATOR_SEND_PAIRING_REQUEST:/* ... */
#endif
break;
default:
done = false;
break;default
}switch (sm_connection->sm_engine_state) { ... }
if (done){
sm_active_connection_handle = sm_connection->sm_handle;
log_info("sm: connection 0x%04x locked setup context as %s, state %u", sm_active_connection_handle, sm_connection->sm_role ? "responder" : "initiator", sm_connection->sm_engine_state);
}if (done) { ... }
}while ((sm_active_connection_handle == HCI_CON_HANDLE_INVALID) && btstack_linked_list_iterator_has_next(&it)) { ... }
}{ ... }
static void sm_run_send_keypress_notification(sm_connection_t * connection){
int i;
uint8_t flags = setup->sm_keypress_notification & 0x1fu;
uint8_t num_actions = setup->sm_keypress_notification >> 5;
uint8_t action = 0;
for (i=SM_KEYPRESS_PASSKEY_ENTRY_STARTED;i<=SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED;i++){
if ((flags & (1u<<i)) != 0u){
bool clear_flag = true;
switch (i){
case SM_KEYPRESS_PASSKEY_ENTRY_STARTED:
case SM_KEYPRESS_PASSKEY_CLEARED:
case SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED:
default:
break;default
case SM_KEYPRESS_PASSKEY_DIGIT_ENTERED:
case SM_KEYPRESS_PASSKEY_DIGIT_ERASED:
num_actions--;
clear_flag = num_actions == 0u;
break;case SM_KEYPRESS_PASSKEY_DIGIT_ERASED:
}switch (i) { ... }
if (clear_flag){
flags &= ~(1<<i);
}if (clear_flag) { ... }
action = i;
break;
}if ((flags & (1u<
}for (i=SM_KEYPRESS_PASSKEY_ENTRY_STARTED;i<=SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED;i++) { ... }
setup->sm_keypress_notification = (num_actions << 5) | flags;
uint8_t buffer[2];
buffer[0] = SM_CODE_KEYPRESS_NOTIFICATION;
buffer[1] = action;
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
l2cap_request_can_send_fix_channel_now_event(sm_active_connection_handle, connection->sm_cid);
}{ ... }
static void sm_run_distribute_keys(sm_connection_t * connection){
if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION) != 0u){
setup->sm_key_distribution_send_set &= ~SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION;
setup->sm_key_distribution_sent_set |= SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION;
uint8_t buffer[17];
buffer[0] = SM_CODE_ENCRYPTION_INFORMATION;
reverse_128(setup->sm_ltk, &buffer[1]);
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
return;
}if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION) != 0u) { ... }
if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION) != 0u){
setup->sm_key_distribution_send_set &= ~SM_KEYDIST_FLAG_MASTER_IDENTIFICATION;
setup->sm_key_distribution_sent_set |= SM_KEYDIST_FLAG_MASTER_IDENTIFICATION;
uint8_t buffer[11];
buffer[0] = SM_CODE_MASTER_IDENTIFICATION;
little_endian_store_16(buffer, 1, setup->sm_local_ediv);
reverse_64(setup->sm_local_rand, &buffer[3]);
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
return;
}if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_MASTER_IDENTIFICATION) != 0u) { ... }
if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION) != 0u){
setup->sm_key_distribution_send_set &= ~SM_KEYDIST_FLAG_IDENTITY_INFORMATION;
setup->sm_key_distribution_sent_set |= SM_KEYDIST_FLAG_IDENTITY_INFORMATION;
uint8_t buffer[17];
buffer[0] = SM_CODE_IDENTITY_INFORMATION;
reverse_128(sm_persistent_irk, &buffer[1]);
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
return;
}if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_IDENTITY_INFORMATION) != 0u) { ... }
if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION) != 0u){
setup->sm_key_distribution_send_set &= ~SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION;
setup->sm_key_distribution_sent_set |= SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION;
bd_addr_t local_address;
uint8_t buffer[8];
buffer[0] = SM_CODE_IDENTITY_ADDRESS_INFORMATION;
switch (gap_random_address_get_mode()){
case GAP_RANDOM_ADDRESS_TYPE_OFF:
case GAP_RANDOM_ADDRESS_TYPE_STATIC:
gap_le_get_own_address(&buffer[1], local_address);
break;case GAP_RANDOM_ADDRESS_TYPE_STATIC:
case GAP_RANDOM_ADDRESS_NON_RESOLVABLE:
case GAP_RANDOM_ADDRESS_RESOLVABLE:
gap_local_bd_addr(local_address);
buffer[1] = 0;
break;case GAP_RANDOM_ADDRESS_RESOLVABLE:
default:
btstack_assert(false);
break;default
}switch (gap_random_address_get_mode()) { ... }
reverse_bd_addr(local_address, &buffer[2]);
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
return;
}if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION) != 0u) { ... }
if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION) != 0u){
setup->sm_key_distribution_send_set &= ~SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION;
setup->sm_key_distribution_sent_set |= SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION;
#ifdef ENABLE_LE_SIGNED_WRITE
if (test_use_fixed_local_csrk){
memset(setup->sm_local_csrk, 0xcc, 16);
}if (test_use_fixed_local_csrk) { ... }
if (setup->sm_le_device_index >= 0){
log_info("sm: store local CSRK");
le_device_db_local_csrk_set(setup->sm_le_device_index, setup->sm_local_csrk);
le_device_db_local_counter_set(setup->sm_le_device_index, 0);
}if (setup->sm_le_device_index >= 0) { ... }
/* ... */#endif
uint8_t buffer[17];
buffer[0] = SM_CODE_SIGNING_INFORMATION;
reverse_128(setup->sm_local_csrk, &buffer[1]);
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
return;
}if ((setup->sm_key_distribution_send_set & SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION) != 0u) { ... }
btstack_assert(false);
}{ ... }
static bool sm_ctkd_from_le(sm_connection_t *sm_connection) {
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
if (setup->sm_use_secure_connections == 0) return false;
bool bonding_enabled = (sm_pairing_packet_get_auth_req(setup->sm_m_preq) & sm_pairing_packet_get_auth_req(setup->sm_s_pres) & SM_AUTHREQ_BONDING ) != 0u;
if (!bonding_enabled) return false;
bool have_identity_address_info = ((setup->sm_key_distribution_received_set & SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION) != 0) || (setup->sm_peer_addr_type == 0);
if (!have_identity_address_info) return false;
uint8_t link_key[16];
link_key_type_t link_key_type;
bool have_link_key = gap_get_link_key_for_bd_addr(setup->sm_peer_address, link_key, &link_key_type);
bool link_key_authenticated = gap_authenticated_for_link_key_type(link_key_type);
bool derived_key_authenticated = sm_connection->sm_connection_authenticated != 0;
if (have_link_key && link_key_authenticated && !derived_key_authenticated) {
return false;
}if (have_link_key && link_key_authenticated && !derived_key_authenticated) { ... }
return true;/* ... */
#else
UNUSED(sm_connection);
return false;/* ... */
#endif
}{ ... }
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
static bool sm_ctkd_from_classic(sm_connection_t * sm_connection){
hci_connection_t * hci_connection = hci_connection_for_handle(sm_connection->sm_handle);
btstack_assert(hci_connection != NULL);
if (gap_secure_connection_for_link_key_type(hci_connection->link_key_type) == false) return false;
bool link_key_authenticated = gap_authenticated_for_link_key_type(hci_connection->link_key_type);
if (link_key_authenticated) return true;
int index = sm_le_device_db_index_lookup(BD_ADDR_TYPE_LE_PUBLIC, hci_connection->address);
if (index >= 0){
int ltk_authenticated;
sm_key_t ltk;
le_device_db_encryption_get(sm_connection->sm_le_db_index, NULL, NULL, ltk, NULL, <k_authenticated, NULL, NULL);
bool have_ltk = !sm_is_null_key(ltk);
if (have_ltk && ltk_authenticated) return false;
}if (index >= 0) { ... }
return true;
}sm_ctkd_from_classic (sm_connection_t * sm_connection) { ... }
/* ... */#endif
static void sm_key_distribution_complete_responder(sm_connection_t * connection){
if (sm_ctkd_from_le(connection)){
bool use_h7 = (sm_pairing_packet_get_auth_req(setup->sm_m_preq) & sm_pairing_packet_get_auth_req(setup->sm_s_pres) & SM_AUTHREQ_CT2) != 0;
connection->sm_engine_state = use_h7 ? SM_SC_W2_CALCULATE_ILK_USING_H7 : SM_SC_W2_CALCULATE_ILK_USING_H6;
}if (sm_ctkd_from_le(connection)) { ... } else {
connection->sm_engine_state = SM_RESPONDER_IDLE;
sm_pairing_complete(connection, ERROR_CODE_SUCCESS, 0);
sm_done_for_handle(connection->sm_handle);
}else { ... }
}{ ... }
static void sm_key_distribution_complete_initiator(sm_connection_t * connection){
if (sm_ctkd_from_le(connection)){
bool use_h7 = (sm_pairing_packet_get_auth_req(setup->sm_m_preq) & sm_pairing_packet_get_auth_req(setup->sm_s_pres) & SM_AUTHREQ_CT2) != 0;
connection->sm_engine_state = use_h7 ? SM_SC_W2_CALCULATE_ILK_USING_H7 : SM_SC_W2_CALCULATE_ILK_USING_H6;
}if (sm_ctkd_from_le(connection)) { ... } else {
sm_master_pairing_success(connection);
}else { ... }
}{ ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static void sm_run_state_sc_send_confirmation(sm_connection_t *connection) {
uint8_t buffer[17];
buffer[0] = SM_CODE_PAIRING_CONFIRM;
reverse_128(setup->sm_local_confirm, &buffer[1]);
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_SC_W4_PAIRING_RANDOM;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_SC_W4_CONFIRMATION;
}else { ... }
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
}sm_run_state_sc_send_confirmation (sm_connection_t *connection) { ... }
static void sm_run_state_sc_send_pairing_random(sm_connection_t *connection) {
uint8_t buffer[17];
buffer[0] = SM_CODE_PAIRING_RANDOM;
reverse_128(setup->sm_local_nonce, &buffer[1]);
log_info("stk method %u, bit num: %u", setup->sm_stk_generation_method, setup->sm_passkey_bit);
if (sm_passkey_entry(setup->sm_stk_generation_method) && (setup->sm_passkey_bit < 20u)){
log_info("SM_SC_SEND_PAIRING_RANDOM A");
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_SC_W4_CONFIRMATION;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_SC_W4_PAIRING_RANDOM;
}else { ... }
}if (sm_passkey_entry(setup->sm_stk_generation_method) && (setup->sm_passkey_bit < 20u)) { ... } else {
log_info("SM_SC_SEND_PAIRING_RANDOM B");
if (IS_RESPONDER(connection->sm_role)){
if (setup->sm_stk_generation_method == NUMERIC_COMPARISON){
log_info("SM_SC_SEND_PAIRING_RANDOM B1");
connection->sm_engine_state = SM_SC_W2_CALCULATE_G2;
}if (setup->sm_stk_generation_method == NUMERIC_COMPARISON) { ... } else {
log_info("SM_SC_SEND_PAIRING_RANDOM B2");
sm_sc_prepare_dhkey_check(connection);
}else { ... }
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_SC_W4_PAIRING_RANDOM;
}else { ... }
}else { ... }
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
}sm_run_state_sc_send_pairing_random (sm_connection_t *connection) { ... }
static void sm_run_state_sc_send_dhkey_check_command(sm_connection_t *connection) {
uint8_t buffer[17];
buffer[0] = SM_CODE_PAIRING_DHKEY_CHECK;
reverse_128(setup->sm_local_dhkey_check, &buffer[1]);
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_SC_W4_LTK_REQUEST_SC;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_SC_W4_DHKEY_CHECK_COMMAND;
}else { ... }
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
}sm_run_state_sc_send_dhkey_check_command (sm_connection_t *connection) { ... }
static void sm_run_state_sc_send_public_key_command(sm_connection_t *connection) {
bool trigger_user_response = false;
bool trigger_start_calculating_local_confirm = false;
uint8_t buffer[65];
buffer[0] = SM_CODE_PAIRING_PUBLIC_KEY;
reverse_256(&ec_q[0], &buffer[1]);
reverse_256(&ec_q[32], &buffer[33]);
#ifdef ENABLE_TESTING_SUPPORT
if (test_pairing_failure == SM_REASON_DHKEY_CHECK_FAILED){
log_info("testing_support: invalidating public key");
buffer[1] ^= 1;
}if (test_pairing_failure == SM_REASON_DHKEY_CHECK_FAILED) { ... }
/* ... */#endif
switch (setup->sm_stk_generation_method){
case JUST_WORKS:
case NUMERIC_COMPARISON:
if (IS_RESPONDER(connection->sm_role)){
trigger_start_calculating_local_confirm = true;
connection->sm_engine_state = SM_SC_W4_LOCAL_NONCE;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_SC_W4_PUBLIC_KEY_COMMAND;
}else { ... }
break;case NUMERIC_COMPARISON:
case PK_INIT_INPUT:
case PK_RESP_INPUT:
case PK_BOTH_INPUT:
(void)memcpy(setup->sm_ra, setup->sm_tk, 16);
(void)memcpy(setup->sm_rb, setup->sm_tk, 16);
setup->sm_passkey_bit = 0;
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_SC_W4_CONFIRMATION;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_SC_W4_PUBLIC_KEY_COMMAND;
}else { ... }
trigger_user_response = true;
break;case PK_BOTH_INPUT:
case OOB:
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_SC_W4_PAIRING_RANDOM;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_SC_W4_PUBLIC_KEY_COMMAND;
}else { ... }
break;case OOB:
default:
btstack_assert(false);
break;default
}switch (setup->sm_stk_generation_method) { ... }
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
if (trigger_user_response){
sm_trigger_user_response(connection);
}if (trigger_user_response) { ... }
if (trigger_start_calculating_local_confirm){
sm_sc_start_calculating_local_confirm(connection);
}if (trigger_start_calculating_local_confirm) { ... }
}sm_run_state_sc_send_public_key_command (sm_connection_t *connection) { ... }
/* ... */#endif
static bool sm_run_non_connection_logic(void){
bool done;;
done = sm_run_dpkg();
if (done) return true;
done = sm_run_rau();
if (done) return true;
done = sm_run_irk_lookup();
if (done) return true;
done = sm_run_oob();
return done;
}{ ... }
static void sm_run(void){
if (hci_get_state() != HCI_STATE_WORKING) return;
if (!hci_can_send_command_packet_now()) return;
if (sm_persistent_keys_random_active) return;
bool done = sm_run_non_connection_logic();
if (done) return;
if (!hci_can_send_command_packet_now()) return;
done = sm_run_basic();
if (done) return;
while (true) {
sm_run_activate_connection();
if (sm_active_connection_handle == HCI_CON_HANDLE_INVALID) return;
sm_connection_t * connection = sm_get_connection_for_handle(sm_active_connection_handle);
if (!connection) {
log_info("no connection for handle 0x%04x", sm_active_connection_handle);
return;
}if (!connection) { ... }
if (!l2cap_can_send_fixed_channel_packet_now(sm_active_connection_handle, connection->sm_cid)) {
log_info("cannot send now, requesting can send now event");
l2cap_request_can_send_fix_channel_now_event(sm_active_connection_handle, connection->sm_cid);
return;
}if (!l2cap_can_send_fixed_channel_packet_now(sm_active_connection_handle, connection->sm_cid)) { ... }
if (setup->sm_keypress_notification != 0u){
sm_run_send_keypress_notification(connection);
return;
}if (setup->sm_keypress_notification != 0u) { ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (sm_cmac_ready() == false){
break;
}if (sm_cmac_ready() == false) { ... }
/* ... */#endif
int key_distribution_flags;
UNUSED(key_distribution_flags);
#ifdef ENABLE_LE_PERIPHERAL
int err;
bool have_ltk;
uint8_t ltk[16];/* ... */
#endif
log_info("sm_run: state %u", connection->sm_engine_state);
switch (connection->sm_engine_state){
#ifdef ENABLE_LE_SECURE_CONNECTIONS
case SM_SC_W2_CMAC_FOR_CONFIRMATION:
connection->sm_engine_state = SM_SC_W4_CMAC_FOR_CONFIRMATION;
sm_sc_calculate_local_confirm(connection);
break;case SM_SC_W2_CMAC_FOR_CONFIRMATION:
case SM_SC_W2_CMAC_FOR_CHECK_CONFIRMATION:
connection->sm_engine_state = SM_SC_W4_CMAC_FOR_CHECK_CONFIRMATION;
sm_sc_calculate_remote_confirm(connection);
break;case SM_SC_W2_CMAC_FOR_CHECK_CONFIRMATION:
case SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK:
connection->sm_engine_state = SM_SC_W4_CALCULATE_F6_FOR_DHKEY_CHECK;
sm_sc_calculate_f6_for_dhkey_check(connection);
break;case SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK:
case SM_SC_W2_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK:
connection->sm_engine_state = SM_SC_W4_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK;
sm_sc_calculate_f6_to_verify_dhkey_check(connection);
break;case SM_SC_W2_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK:
case SM_SC_W2_CALCULATE_F5_SALT:
connection->sm_engine_state = SM_SC_W4_CALCULATE_F5_SALT;
f5_calculate_salt(connection);
break;case SM_SC_W2_CALCULATE_F5_SALT:
case SM_SC_W2_CALCULATE_F5_MACKEY:
connection->sm_engine_state = SM_SC_W4_CALCULATE_F5_MACKEY;
f5_calculate_mackey(connection);
break;case SM_SC_W2_CALCULATE_F5_MACKEY:
case SM_SC_W2_CALCULATE_F5_LTK:
connection->sm_engine_state = SM_SC_W4_CALCULATE_F5_LTK;
f5_calculate_ltk(connection);
break;case SM_SC_W2_CALCULATE_F5_LTK:
case SM_SC_W2_CALCULATE_G2:
connection->sm_engine_state = SM_SC_W4_CALCULATE_G2;
g2_calculate(connection);
break;/* ... */
#endif
#ifdef ENABLE_LE_CENTRAL
case SM_INITIATOR_PH4_HAS_LTK: {
sm_reset_setup();
sm_load_security_info(connection);
sm_cache_ltk(connection, setup->sm_peer_ltk);
sm_key_t peer_ltk_flipped;
reverse_128(setup->sm_peer_ltk, peer_ltk_flipped);
connection->sm_engine_state = SM_PH4_W4_CONNECTION_ENCRYPTED;
log_info("sm: hci_le_start_encryption ediv 0x%04x", setup->sm_peer_ediv);
uint32_t rand_high = big_endian_read_32(setup->sm_peer_rand, 0);
uint32_t rand_low = big_endian_read_32(setup->sm_peer_rand, 4);
hci_send_cmd(&hci_le_start_encryption, connection->sm_handle,rand_low, rand_high, setup->sm_peer_ediv, peer_ltk_flipped);
sm_reencryption_started(connection);
return;
...}
case SM_INITIATOR_PH4_HAS_LTK:
case SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST:
sm_reset_setup();
sm_init_setup(connection);
sm_pairing_packet_set_code(setup->sm_m_preq, SM_CODE_PAIRING_REQUEST);
connection->sm_engine_state = SM_INITIATOR_PH1_W4_PAIRING_RESPONSE;
sm_send_connectionless(connection, (uint8_t*) &setup->sm_m_preq, sizeof(sm_pairing_packet_t));
sm_timeout_reset(connection);
sm_pairing_started(connection);
break;/* ... */
#endif
#ifdef ENABLE_LE_SECURE_CONNECTIONS
case SM_SC_SEND_PUBLIC_KEY_COMMAND:
sm_run_state_sc_send_public_key_command(connection);
break;case SM_SC_SEND_PUBLIC_KEY_COMMAND:
case SM_SC_SEND_CONFIRMATION:
sm_run_state_sc_send_confirmation(connection);
break;case SM_SC_SEND_CONFIRMATION:
case SM_SC_SEND_PAIRING_RANDOM:
sm_run_state_sc_send_pairing_random(connection);
break;case SM_SC_SEND_PAIRING_RANDOM:
case SM_SC_SEND_DHKEY_CHECK_COMMAND:
sm_run_state_sc_send_dhkey_check_command(connection);
break;/* ... */
#endif
#ifdef ENABLE_LE_PERIPHERAL
case SM_RESPONDER_SEND_SECURITY_REQUEST: {
const uint8_t buffer[2] = {SM_CODE_SECURITY_REQUEST, sm_auth_req};
connection->sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_REQUEST;
sm_send_connectionless(connection, (uint8_t *) buffer, sizeof(buffer));
sm_timeout_start(connection);
break;
...}
#ifdef ENABLE_LE_SECURE_CONNECTIONScase SM_RESPONDER_SEND_SECURITY_REQUEST:
case SM_SC_RECEIVED_LTK_REQUEST:
switch (connection->sm_irk_lookup_state){
case IRK_LOOKUP_SUCCEEDED:
sm_reset_setup();
sm_load_security_info(connection);
if ((setup->sm_peer_ediv == 0u) && sm_is_null_random(setup->sm_peer_rand) && !sm_is_null_key(setup->sm_peer_ltk)){
(void)memcpy(setup->sm_ltk, setup->sm_peer_ltk, 16);
connection->sm_engine_state = SM_RESPONDER_PH4_SEND_LTK_REPLY;
sm_reencryption_started(connection);
sm_trigger_run();
break;
}if ((setup->sm_peer_ediv == 0u) && sm_is_null_random(setup->sm_peer_rand) && !sm_is_null_key(setup->sm_peer_ltk)) { ... }
log_info("LTK Request: ediv & random are empty, but no stored LTK (IRK Lookup Succeeded)");
connection->sm_engine_state = SM_RESPONDER_IDLE;
hci_send_cmd(&hci_le_long_term_key_negative_reply, connection->sm_handle);
return;case IRK_LOOKUP_SUCCEEDED:
default:
break;default
}switch (connection->sm_irk_lookup_state) { ... }
break;/* ... */
#endif
case SM_SC_RECEIVED_LTK_REQUEST:
case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED:
sm_reset_setup();
switch (connection->sm_irk_lookup_state) {
case IRK_LOOKUP_SUCCEEDED:
le_device_db_encryption_get(connection->sm_le_db_index, NULL, NULL, ltk, NULL, NULL, NULL, NULL);
have_ltk = !sm_is_null_key(ltk);
if (have_ltk){
log_info("pairing request but LTK available");
sm_reencryption_started(connection);
sm_reencryption_complete(connection, ERROR_CODE_PIN_OR_KEY_MISSING);
}if (have_ltk) { ... }
break;case IRK_LOOKUP_SUCCEEDED:
default:
break;default
}switch (connection->sm_irk_lookup_state) { ... }
sm_init_setup(connection);
(void)memcpy(&setup->sm_m_preq, &connection->sm_m_preq, sizeof(sm_pairing_packet_t));
err = sm_stk_generation_init(connection);
#ifdef ENABLE_TESTING_SUPPORT
if ((0 < test_pairing_failure) && (test_pairing_failure < SM_REASON_DHKEY_CHECK_FAILED)){
log_info("testing_support: respond with pairing failure %u", test_pairing_failure);
err = test_pairing_failure;
}if ((0 < test_pairing_failure) && (test_pairing_failure < SM_REASON_DHKEY_CHECK_FAILED)) { ... }
/* ... */#endif
if (err != 0){
sm_pairing_started(connection);
sm_pairing_error(connection, err);
sm_trigger_run();
break;
}if (err != 0) { ... }
sm_timeout_start(connection);
if (setup->sm_stk_generation_method == PK_INIT_INPUT){
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_data, 8, &sm_handle_random_result_ph2_tk, (void *)(uintptr_t) connection->sm_handle);
break;
}if (setup->sm_stk_generation_method == PK_INIT_INPUT) { ... }
case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED:
case SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE:
sm_pairing_packet_set_code(setup->sm_s_pres,SM_CODE_PAIRING_RESPONSE);
key_distribution_flags = sm_key_distribution_flags_for_auth_req();
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (setup->sm_use_secure_connections){
key_distribution_flags &= ~SM_KEYDIST_ENC_KEY;
}if (setup->sm_use_secure_connections) { ... }
/* ... */#endif
sm_pairing_packet_set_initiator_key_distribution(setup->sm_s_pres, sm_pairing_packet_get_initiator_key_distribution(setup->sm_m_preq) & key_distribution_flags);
sm_pairing_packet_set_responder_key_distribution(setup->sm_s_pres, sm_pairing_packet_get_responder_key_distribution(setup->sm_m_preq) & key_distribution_flags);
sm_setup_key_distribution(sm_pairing_packet_get_responder_key_distribution(setup->sm_s_pres), sm_pairing_packet_get_initiator_key_distribution(setup->sm_s_pres));
if (setup->sm_use_secure_connections){
connection->sm_engine_state = SM_SC_W4_PUBLIC_KEY_COMMAND;
}if (setup->sm_use_secure_connections) { ... } else {
connection->sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_CONFIRM;
}else { ... }
sm_send_connectionless(connection, (uint8_t*) &setup->sm_s_pres, sizeof(sm_pairing_packet_t));
sm_timeout_reset(connection);
sm_pairing_started(connection);
if (!setup->sm_use_secure_connections || (setup->sm_stk_generation_method == JUST_WORKS)){
sm_trigger_user_response(connection);
}if (!setup->sm_use_secure_connections || (setup->sm_stk_generation_method == JUST_WORKS)) { ... }
return;/* ... */
#endif
case SM_PH2_SEND_PAIRING_RANDOM: {
uint8_t buffer[17];
buffer[0] = SM_CODE_PAIRING_RANDOM;
reverse_128(setup->sm_local_random, &buffer[1]);
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_RESPONDER_PH2_W4_LTK_REQUEST;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_INITIATOR_PH2_W4_PAIRING_RANDOM;
}else { ... }
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
break;
...}
case SM_PH2_SEND_PAIRING_RANDOM:
case SM_PH2_C1_GET_ENC_A:
if (sm_aes128_state == SM_AES128_ACTIVE) break;
sm_c1_t1(setup->sm_local_random, (uint8_t*) &setup->sm_m_preq, (uint8_t*) &setup->sm_s_pres, setup->sm_m_addr_type, setup->sm_s_addr_type, sm_aes128_plaintext);
connection->sm_engine_state = SM_PH2_C1_W4_ENC_A;
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, setup->sm_tk, sm_aes128_plaintext, sm_aes128_ciphertext, sm_handle_encryption_result_enc_a, (void *)(uintptr_t) connection->sm_handle);
break;
case SM_PH2_C1_GET_ENC_A:
case SM_PH2_C1_GET_ENC_C:
if (sm_aes128_state == SM_AES128_ACTIVE) break;
sm_c1_t1(setup->sm_peer_random, (uint8_t*) &setup->sm_m_preq, (uint8_t*) &setup->sm_s_pres, setup->sm_m_addr_type, setup->sm_s_addr_type, sm_aes128_plaintext);
connection->sm_engine_state = SM_PH2_C1_W4_ENC_C;
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, setup->sm_tk, sm_aes128_plaintext, sm_aes128_ciphertext, sm_handle_encryption_result_enc_c, (void *)(uintptr_t) connection->sm_handle);
break;
case SM_PH2_C1_GET_ENC_C:
case SM_PH2_CALC_STK:
if (sm_aes128_state == SM_AES128_ACTIVE) break;
if (IS_RESPONDER(connection->sm_role)){
sm_s1_r_prime(setup->sm_local_random, setup->sm_peer_random, sm_aes128_plaintext);
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
sm_s1_r_prime(setup->sm_peer_random, setup->sm_local_random, sm_aes128_plaintext);
}else { ... }
connection->sm_engine_state = SM_PH2_W4_STK;
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, setup->sm_tk, sm_aes128_plaintext, setup->sm_ltk, sm_handle_encryption_result_enc_stk, (void *)(uintptr_t) connection->sm_handle);
break;
case SM_PH2_CALC_STK:
case SM_PH3_Y_GET_ENC:
if (sm_aes128_state == SM_AES128_ACTIVE) break;
memset(&sm_aes128_plaintext[0], 0, 8);
(void)memcpy(&sm_aes128_plaintext[8], setup->sm_local_rand, 8);
connection->sm_engine_state = SM_PH3_Y_W4_ENC;
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_persistent_dhk, sm_aes128_plaintext, sm_aes128_ciphertext, sm_handle_encryption_result_enc_ph3_y, (void *)(uintptr_t) connection->sm_handle);
break;
case SM_PH3_Y_GET_ENC:
case SM_PH2_C1_SEND_PAIRING_CONFIRM: {
uint8_t buffer[17];
buffer[0] = SM_CODE_PAIRING_CONFIRM;
reverse_128(setup->sm_local_confirm, &buffer[1]);
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_RESPONDER_PH2_W4_PAIRING_RANDOM;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_INITIATOR_PH2_W4_PAIRING_CONFIRM;
}else { ... }
sm_send_connectionless(connection, (uint8_t*) buffer, sizeof(buffer));
sm_timeout_reset(connection);
return;
...}
#ifdef ENABLE_LE_PERIPHERALcase SM_PH2_C1_SEND_PAIRING_CONFIRM:
case SM_RESPONDER_PH2_SEND_LTK_REPLY: {
sm_cache_ltk(connection, setup->sm_ltk);
sm_key_t stk_flipped;
reverse_128(setup->sm_ltk, stk_flipped);
connection->sm_engine_state = SM_PH2_W4_CONNECTION_ENCRYPTED;
hci_send_cmd(&hci_le_long_term_key_request_reply, connection->sm_handle, stk_flipped);
return;
...}case SM_RESPONDER_PH2_SEND_LTK_REPLY:
case SM_RESPONDER_PH4_SEND_LTK_REPLY: {
if (sm_get_ltk_callback != NULL){
(void)(*sm_get_ltk_callback)(connection->sm_handle, connection->sm_peer_addr_type, connection->sm_peer_address, setup->sm_ltk);
}if (sm_get_ltk_callback != NULL) { ... }
sm_cache_ltk(connection, setup->sm_ltk);
sm_key_t ltk_flipped;
reverse_128(setup->sm_ltk, ltk_flipped);
connection->sm_engine_state = SM_PH4_W4_CONNECTION_ENCRYPTED;
hci_send_cmd(&hci_le_long_term_key_request_reply, connection->sm_handle, ltk_flipped);
return;
...}
case SM_RESPONDER_PH4_SEND_LTK_REPLY:
case SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST:
if (sm_aes128_state == SM_AES128_ACTIVE) break;
log_info("LTK Request: recalculating with ediv 0x%04x", setup->sm_local_ediv);
sm_reset_setup();
sm_start_calculating_ltk_from_ediv_and_rand(connection);
sm_reencryption_started(connection);
memset(&sm_aes128_plaintext[0], 0, 8);
(void)memcpy(&sm_aes128_plaintext[8], setup->sm_local_rand, 8);
connection->sm_engine_state = SM_RESPONDER_PH4_Y_W4_ENC;
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_persistent_dhk, sm_aes128_plaintext, sm_aes128_ciphertext, sm_handle_encryption_result_enc_ph4_y, (void *)(uintptr_t) connection->sm_handle);
return;/* ... */
#endif
#ifdef ENABLE_LE_CENTRAL
case SM_INITIATOR_PH3_SEND_START_ENCRYPTION: {
sm_cache_ltk(connection, setup->sm_ltk);
sm_key_t stk_flipped;
reverse_128(setup->sm_ltk, stk_flipped);
connection->sm_engine_state = SM_PH2_W4_CONNECTION_ENCRYPTED;
hci_send_cmd(&hci_le_start_encryption, connection->sm_handle, 0, 0, 0, stk_flipped);
return;
...}/* ... */
#endif
case SM_INITIATOR_PH3_SEND_START_ENCRYPTION:
case SM_PH3_DISTRIBUTE_KEYS:
if (setup->sm_key_distribution_send_set != 0){
sm_run_distribute_keys(connection);
}if (setup->sm_key_distribution_send_set != 0) { ... }
if (setup->sm_key_distribution_send_set != 0){
return;
}if (setup->sm_key_distribution_send_set != 0) { ... }
if (IS_RESPONDER(connection->sm_role)){
if (sm_key_distribution_all_received()){
sm_key_distribution_handle_all_received(connection);
sm_key_distribution_complete_responder(connection);
continue;
}if (sm_key_distribution_all_received()) { ... } else {
connection->sm_engine_state = SM_PH3_RECEIVE_KEYS;
}else { ... }
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
sm_master_pairing_success(connection);
}else { ... }
break;
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATIONcase SM_PH3_DISTRIBUTE_KEYS:
case SM_BR_EDR_INITIATOR_SEND_PAIRING_REQUEST:
sm_reset_setup();
setup->sm_peer_addr_type = connection->sm_peer_addr_type;
setup->sm_m_addr_type = connection->sm_peer_addr_type;
setup->sm_s_addr_type = connection->sm_own_addr_type;
(void) memcpy(setup->sm_peer_address, connection->sm_peer_address, 6);
(void) memcpy(setup->sm_m_address, connection->sm_peer_address, 6);
(void) memcpy(setup->sm_s_address, connection->sm_own_address, 6);
setup->sm_use_secure_connections = true;
sm_ctkd_fetch_br_edr_link_key(connection);
key_distribution_flags = SM_KEYDIST_ID_KEY | SM_KEYDIST_ENC_KEY;
#ifdef ENABLE_LE_SIGNED_WRITE
key_distribution_flags |= SM_KEYDIST_ID_KEY;/* ... */
#endif
sm_pairing_packet_set_code(setup->sm_m_preq, SM_CODE_PAIRING_REQUEST);
sm_pairing_packet_set_io_capability(setup->sm_m_preq, 0);
sm_pairing_packet_set_oob_data_flag(setup->sm_m_preq, 0);
sm_pairing_packet_set_auth_req(setup->sm_m_preq, SM_AUTHREQ_CT2);
sm_pairing_packet_set_max_encryption_key_size(setup->sm_m_preq, sm_max_encryption_key_size);
sm_pairing_packet_set_initiator_key_distribution(setup->sm_m_preq, key_distribution_flags);
sm_pairing_packet_set_responder_key_distribution(setup->sm_m_preq, key_distribution_flags);
sm_timeout_start(connection);
connection->sm_engine_state = SM_BR_EDR_INITIATOR_W4_PAIRING_RESPONSE;
sm_send_connectionless(connection, (uint8_t *) &setup->sm_m_preq, sizeof(sm_pairing_packet_t));
break;
case SM_BR_EDR_INITIATOR_SEND_PAIRING_REQUEST:
case SM_BR_EDR_RESPONDER_PAIRING_REQUEST_RECEIVED:
sm_reset_setup();
setup->sm_peer_addr_type = connection->sm_peer_addr_type;
setup->sm_m_addr_type = connection->sm_peer_addr_type;
setup->sm_s_addr_type = connection->sm_own_addr_type;
(void) memcpy(setup->sm_peer_address, connection->sm_peer_address, 6);
(void) memcpy(setup->sm_m_address, connection->sm_peer_address, 6);
(void) memcpy(setup->sm_s_address, connection->sm_own_address, 6);
setup->sm_use_secure_connections = true;
sm_ctkd_fetch_br_edr_link_key(connection);
(void) memcpy(&setup->sm_m_preq, &connection->sm_m_preq, sizeof(sm_pairing_packet_t));
key_distribution_flags = SM_KEYDIST_ID_KEY | SM_KEYDIST_ENC_KEY;
#ifdef ENABLE_LE_SIGNED_WRITE
key_distribution_flags |= SM_KEYDIST_ID_KEY;/* ... */
#endif
key_distribution_flags &= sm_pairing_packet_get_initiator_key_distribution(connection->sm_m_preq);
sm_pairing_packet_set_code(setup->sm_s_pres, SM_CODE_PAIRING_RESPONSE);
sm_pairing_packet_set_io_capability(setup->sm_s_pres, 0);
sm_pairing_packet_set_oob_data_flag(setup->sm_s_pres, 0);
sm_pairing_packet_set_auth_req(setup->sm_s_pres, SM_AUTHREQ_CT2);
sm_pairing_packet_set_max_encryption_key_size(setup->sm_s_pres, connection->sm_actual_encryption_key_size);
sm_pairing_packet_set_initiator_key_distribution(setup->sm_s_pres, key_distribution_flags);
sm_pairing_packet_set_responder_key_distribution(setup->sm_s_pres, key_distribution_flags);
key_distribution_flags &= ~SM_KEYDIST_ENC_KEY;
sm_setup_key_distribution(key_distribution_flags, key_distribution_flags);
sm_timeout_start(connection);
connection->sm_engine_state = SM_BR_EDR_DISTRIBUTE_KEYS;
sm_send_connectionless(connection, (uint8_t *) &setup->sm_s_pres, sizeof(sm_pairing_packet_t));
break;case SM_BR_EDR_RESPONDER_PAIRING_REQUEST_RECEIVED:
case SM_BR_EDR_DISTRIBUTE_KEYS:
if (setup->sm_key_distribution_send_set != 0) {
sm_run_distribute_keys(connection);
return;
}if (setup->sm_key_distribution_send_set != 0) { ... }
if (IS_RESPONDER(connection->sm_role)) {
if (!sm_key_distribution_all_received()){
connection->sm_engine_state = SM_BR_EDR_RECEIVE_KEYS;
break;
}if (!sm_key_distribution_all_received()) { ... }
}if (IS_RESPONDER(connection->sm_role)) { ... }
sm_ctkd_start_from_br_edr(connection);
continue;case SM_BR_EDR_DISTRIBUTE_KEYS:
case SM_SC_W2_CALCULATE_ILK_USING_H6:
connection->sm_engine_state = SM_SC_W4_CALCULATE_ILK;
h6_calculate_ilk_from_le_ltk(connection);
break;case SM_SC_W2_CALCULATE_ILK_USING_H6:
case SM_SC_W2_CALCULATE_BR_EDR_LINK_KEY:
connection->sm_engine_state = SM_SC_W4_CALCULATE_BR_EDR_LINK_KEY;
h6_calculate_br_edr_link_key(connection);
break;case SM_SC_W2_CALCULATE_BR_EDR_LINK_KEY:
case SM_SC_W2_CALCULATE_ILK_USING_H7:
connection->sm_engine_state = SM_SC_W4_CALCULATE_ILK;
h7_calculate_ilk_from_le_ltk(connection);
break;case SM_SC_W2_CALCULATE_ILK_USING_H7:
case SM_BR_EDR_W2_CALCULATE_ILK_USING_H6:
connection->sm_engine_state = SM_BR_EDR_W4_CALCULATE_ILK;
h6_calculate_ilk_from_br_edr(connection);
break;case SM_BR_EDR_W2_CALCULATE_ILK_USING_H6:
case SM_BR_EDR_W2_CALCULATE_LE_LTK:
connection->sm_engine_state = SM_BR_EDR_W4_CALCULATE_LE_LTK;
h6_calculate_le_ltk(connection);
break;case SM_BR_EDR_W2_CALCULATE_LE_LTK:
case SM_BR_EDR_W2_CALCULATE_ILK_USING_H7:
connection->sm_engine_state = SM_BR_EDR_W4_CALCULATE_ILK;
h7_calculate_ilk_from_br_edr(connection);
break;/* ... */
#endif
default:
break;default
}switch (connection->sm_engine_state) { ... }
if (sm_active_connection_handle != HCI_CON_HANDLE_INVALID) break;
}while (true) { ... }
}{ ... }
static void sm_handle_encryption_result_enc_a(void *arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_aes128_state = SM_AES128_IDLE;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
sm_c1_t3(sm_aes128_ciphertext, setup->sm_m_address, setup->sm_s_address, setup->sm_c1_t3_value);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, setup->sm_tk, setup->sm_c1_t3_value, setup->sm_local_confirm, sm_handle_encryption_result_enc_b, (void *)(uintptr_t) connection->sm_handle);
}{ ... }
static void sm_handle_encryption_result_enc_b(void *arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_aes128_state = SM_AES128_IDLE;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
log_info_key("c1!", setup->sm_local_confirm);
connection->sm_engine_state = SM_PH2_C1_SEND_PAIRING_CONFIRM;
sm_trigger_run();
}{ ... }
static void sm_handle_encryption_result_enc_c(void *arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_aes128_state = SM_AES128_IDLE;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
sm_c1_t3(sm_aes128_ciphertext, setup->sm_m_address, setup->sm_s_address, setup->sm_c1_t3_value);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, setup->sm_tk, setup->sm_c1_t3_value, sm_aes128_ciphertext, sm_handle_encryption_result_enc_d, (void *)(uintptr_t) connection->sm_handle);
}{ ... }
static void sm_handle_encryption_result_enc_d(void * arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_aes128_state = SM_AES128_IDLE;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
log_info_key("c1!", sm_aes128_ciphertext);
if (memcmp(setup->sm_peer_confirm, sm_aes128_ciphertext, 16) != 0){
sm_pairing_error(connection, SM_REASON_CONFIRM_VALUE_FAILED);
sm_trigger_run();
return;
}if (memcmp(setup->sm_peer_confirm, sm_aes128_ciphertext, 16) != 0) { ... }
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_PH2_SEND_PAIRING_RANDOM;
sm_trigger_run();
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
sm_s1_r_prime(setup->sm_peer_random, setup->sm_local_random, sm_aes128_plaintext);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, setup->sm_tk, sm_aes128_plaintext, setup->sm_ltk, sm_handle_encryption_result_enc_stk, (void *)(uintptr_t) connection->sm_handle);
}else { ... }
}{ ... }
static void sm_handle_encryption_result_enc_stk(void *arg){
sm_aes128_state = SM_AES128_IDLE;
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
sm_truncate_key(setup->sm_ltk, connection->sm_actual_encryption_key_size);
log_info_key("stk", setup->sm_ltk);
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_RESPONDER_PH2_SEND_LTK_REPLY;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
connection->sm_engine_state = SM_INITIATOR_PH3_SEND_START_ENCRYPTION;
}else { ... }
sm_trigger_run();
}{ ... }
static void sm_handle_encryption_result_enc_ph3_y(void *arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_aes128_state = SM_AES128_IDLE;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
setup->sm_local_y = big_endian_read_16(sm_aes128_ciphertext, 14);
log_info_hex16("y", setup->sm_local_y);
setup->sm_local_ediv = setup->sm_local_y ^ setup->sm_local_div;
log_info_hex16("ediv", setup->sm_local_ediv);
sm_d1_d_prime(setup->sm_local_div, 0, sm_aes128_plaintext);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_persistent_er, sm_aes128_plaintext, setup->sm_ltk, sm_handle_encryption_result_enc_ph3_ltk, (void *)(uintptr_t) connection->sm_handle);
}{ ... }
#ifdef ENABLE_LE_PERIPHERAL
static void sm_handle_encryption_result_enc_ph4_y(void *arg){
sm_aes128_state = SM_AES128_IDLE;
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
setup->sm_local_y = big_endian_read_16(sm_aes128_ciphertext, 14);
log_info_hex16("y", setup->sm_local_y);
setup->sm_local_div = setup->sm_local_y ^ setup->sm_local_ediv;
log_info_hex16("ediv", setup->sm_local_ediv);
sm_d1_d_prime(setup->sm_local_div, 0, sm_aes128_plaintext);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_persistent_er, sm_aes128_plaintext, setup->sm_ltk, sm_handle_encryption_result_enc_ph4_ltk, (void *)(uintptr_t) connection->sm_handle);
}{ ... }
#endif/* ... */
static void sm_handle_encryption_result_enc_ph3_ltk(void *arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_aes128_state = SM_AES128_IDLE;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
log_info_key("ltk", setup->sm_ltk);
sm_d1_d_prime(setup->sm_local_div, 1, sm_aes128_plaintext);
sm_aes128_state = SM_AES128_ACTIVE;
btstack_crypto_aes128_encrypt(&sm_crypto_aes128_request, sm_persistent_er, sm_aes128_plaintext, setup->sm_local_csrk, sm_handle_encryption_result_enc_csrk, (void *)(uintptr_t) connection->sm_handle);
}{ ... }
static void sm_handle_encryption_result_enc_csrk(void *arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_aes128_state = SM_AES128_IDLE;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
sm_aes128_state = SM_AES128_IDLE;
log_info_key("csrk", setup->sm_local_csrk);
if (setup->sm_key_distribution_send_set != 0u){
connection->sm_engine_state = SM_PH3_DISTRIBUTE_KEYS;
}if (setup->sm_key_distribution_send_set != 0u) { ... } else {
if (IS_RESPONDER(connection->sm_role)){
if (sm_key_distribution_all_received()){
sm_key_distribution_handle_all_received(connection);
sm_key_distribution_complete_responder(connection);
}if (sm_key_distribution_all_received()) { ... } else {
connection->sm_engine_state = SM_PH3_RECEIVE_KEYS;
}else { ... }
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
sm_key_distribution_complete_initiator(connection);
}else { ... }
}else { ... }
sm_trigger_run();
}{ ... }
#ifdef ENABLE_LE_PERIPHERAL
static void sm_handle_encryption_result_enc_ph4_ltk(void *arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_aes128_state = SM_AES128_IDLE;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
sm_truncate_key(setup->sm_ltk, connection->sm_actual_encryption_key_size);
log_info_key("ltk", setup->sm_ltk);
connection->sm_engine_state = SM_RESPONDER_PH4_SEND_LTK_REPLY;
sm_trigger_run();
}{ ... }
/* ... */#endif
static void sm_handle_encryption_result_address_resolution(void *arg){
UNUSED(arg);
sm_aes128_state = SM_AES128_IDLE;
uint8_t * hash = &sm_aes128_ciphertext[13];
if (memcmp(&sm_address_resolution_address[3], hash, 3) == 0){
log_info("LE Device Lookup: matched resolvable private address");
sm_address_resolution_handle_event(ADDRESS_RESOLUTION_SUCCEEDED);
sm_trigger_run();
return;
}if (memcmp(&sm_address_resolution_address[3], hash, 3) == 0) { ... }
sm_address_resolution_test++;
sm_trigger_run();
}{ ... }
static void sm_handle_encryption_result_dkg_irk(void *arg){
UNUSED(arg);
sm_aes128_state = SM_AES128_IDLE;
log_info_key("irk", sm_persistent_irk);
dkg_state = DKG_CALC_DHK;
sm_trigger_run();
}{ ... }
static void sm_handle_encryption_result_dkg_dhk(void *arg){
UNUSED(arg);
sm_aes128_state = SM_AES128_IDLE;
log_info_key("dhk", sm_persistent_dhk);
dkg_state = DKG_READY;
sm_trigger_run();
}{ ... }
static void sm_handle_encryption_result_rau(void *arg){
UNUSED(arg);
sm_aes128_state = SM_AES128_IDLE;
(void)memcpy(&sm_random_address[3], &sm_aes128_ciphertext[13], 3);
rau_state = RAU_IDLE;
hci_le_random_address_set(sm_random_address);
sm_trigger_run();
}{ ... }
static void sm_handle_random_result_rau(void * arg){
UNUSED(arg);
switch (gap_random_adress_type){
case GAP_RANDOM_ADDRESS_RESOLVABLE:
sm_random_address[0u] &= 0x3fu;
sm_random_address[0u] |= 0x40u;
rau_state = RAU_GET_ENC;
break;case GAP_RANDOM_ADDRESS_RESOLVABLE:
case GAP_RANDOM_ADDRESS_NON_RESOLVABLE:
default:
sm_random_address[0u] &= 0x3fu;
rau_state = RAU_IDLE;
hci_le_random_address_set(sm_random_address);
break;default
}switch (gap_random_adress_type) { ... }
sm_trigger_run();
}{ ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static void sm_handle_random_result_sc_next_send_pairing_random(void * arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
connection->sm_engine_state = SM_SC_SEND_PAIRING_RANDOM;
sm_trigger_run();
}sm_handle_random_result_sc_next_send_pairing_random (void * arg) { ... }
static void sm_handle_random_result_sc_next_w2_cmac_for_confirmation(void * arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
connection->sm_engine_state = SM_SC_W2_CMAC_FOR_CONFIRMATION;
sm_trigger_run();
}sm_handle_random_result_sc_next_w2_cmac_for_confirmation (void * arg) { ... }
/* ... */#endif
static void sm_handle_random_result_ph2_random(void * arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
connection->sm_engine_state = SM_PH2_C1_GET_ENC_A;
sm_trigger_run();
}{ ... }
static void sm_handle_random_result_ph2_tk(void * arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
sm_reset_tk();
uint32_t tk;
if (sm_fixed_passkey_in_display_role == 0xffffffffU){
tk = little_endian_read_32(sm_random_data,0);
tk = tk & 0xfffff;
if (tk >= 999999u){
tk = tk - 999999u;
}if (tk >= 999999u) { ... }
}if (sm_fixed_passkey_in_display_role == 0xffffffffU) { ... } else {
tk = sm_fixed_passkey_in_display_role;
}else { ... }
big_endian_store_32(setup->sm_tk, 12, tk);
if (IS_RESPONDER(connection->sm_role)){
connection->sm_engine_state = SM_RESPONDER_PH1_SEND_PAIRING_RESPONSE;
}if (IS_RESPONDER(connection->sm_role)) { ... } else {
if (setup->sm_use_secure_connections){
connection->sm_engine_state = SM_SC_SEND_PUBLIC_KEY_COMMAND;
}if (setup->sm_use_secure_connections) { ... } else {
connection->sm_engine_state = SM_PH1_W4_USER_RESPONSE;
sm_trigger_user_response(connection);
if (setup->sm_user_response == SM_USER_RESPONSE_IDLE){
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_random, 16, &sm_handle_random_result_ph2_random, (void *)(uintptr_t) connection->sm_handle);
}if (setup->sm_user_response == SM_USER_RESPONSE_IDLE) { ... }
}else { ... }
}else { ... }
sm_trigger_run();
}{ ... }
static void sm_handle_random_result_ph3_div(void * arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
setup->sm_local_div = big_endian_read_16(sm_random_data, 0);
log_info_hex16("div", setup->sm_local_div);
connection->sm_engine_state = SM_PH3_Y_GET_ENC;
sm_trigger_run();
}{ ... }
static void sm_handle_random_result_ph3_random(void * arg){
hci_con_handle_t con_handle = (hci_con_handle_t) (uintptr_t) arg;
sm_connection_t * connection = sm_get_connection_for_handle(con_handle);
if (connection == NULL) return;
reverse_64(sm_random_data, setup->sm_local_rand);
setup->sm_local_rand[7u] = (setup->sm_local_rand[7u] & 0xf0u) + (connection->sm_actual_encryption_key_size - 1u);
setup->sm_local_rand[7u] = (setup->sm_local_rand[7u] & 0xefu) + (connection->sm_connection_authenticated << 4u);
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_data, 2, &sm_handle_random_result_ph3_div, (void *)(uintptr_t) connection->sm_handle);
}{ ... }
static void sm_validate_er_ir(void){
bool warning = false;
if (sm_ir_is_default()){
warning = true;
log_error("Persistent IR not set with sm_set_ir. Use of private addresses will cause pairing issues");
}if (sm_ir_is_default()) { ... }
if (sm_er_is_default()){
warning = true;
log_error("Persistent ER not set with sm_set_er. Legacy Pairing LTK is not secure");
}if (sm_er_is_default()) { ... }
if (warning) {
log_error("Please configure btstack_tlv to let BTstack setup ER and IR keys");
}if (warning) { ... }
}{ ... }
static void sm_handle_random_result_ir(void *arg){
sm_persistent_keys_random_active = false;
if (arg != NULL){
int status = sm_tlv_impl->store_tag(sm_tlv_context, BTSTACK_TAG32('S','M','I','R'), sm_persistent_ir, 16u);
log_info("Generated IR key. Store in TLV status: %d", status);
UNUSED(status);
}if (arg != NULL) { ... }
log_info_key("IR", sm_persistent_ir);
dkg_state = DKG_CALC_IRK;
if (test_use_fixed_local_irk){
log_info_key("IRK", sm_persistent_irk);
dkg_state = DKG_CALC_DHK;
}if (test_use_fixed_local_irk) { ... }
sm_trigger_run();
}{ ... }
static void sm_handle_random_result_er(void *arg){
sm_persistent_keys_random_active = false;
if (arg != NULL){
int status = sm_tlv_impl->store_tag(sm_tlv_context, BTSTACK_TAG32('S','M','E','R'), sm_persistent_er, 16u);
log_info("Generated ER key. Store in TLV status: %d", status);
UNUSED(status);
}if (arg != NULL) { ... }
log_info_key("ER", sm_persistent_er);
int key_size = sm_tlv_impl->get_tag(sm_tlv_context, BTSTACK_TAG32('S','M','I','R'), sm_persistent_ir, 16u);
if (key_size == 16){
log_info("IR from TLV");
sm_handle_random_result_ir( NULL );
}if (key_size == 16) { ... } else {
sm_persistent_keys_random_active = true;
btstack_crypto_random_generate(&sm_crypto_random_request, sm_persistent_ir, 16, &sm_handle_random_result_ir, &sm_persistent_ir);
}else { ... }
}{ ... }
static void sm_connection_init(sm_connection_t * sm_conn, hci_con_handle_t con_handle, uint8_t role, uint8_t peer_addr_type, bd_addr_t peer_address){
sm_conn->sm_handle = con_handle;
sm_conn->sm_role = role;
sm_conn->sm_peer_addr_type = peer_addr_type;
memcpy(sm_conn->sm_peer_address, peer_address, 6);
sm_conn->sm_connection_encrypted = 0;
sm_conn->sm_connection_authenticated = 0;
sm_conn->sm_connection_authorization_state = AUTHORIZATION_UNKNOWN;
sm_conn->sm_le_db_index = -1;
sm_conn->sm_reencryption_active = false;
sm_conn->sm_irk_lookup_state = IRK_LOOKUP_W4_READY;
sm_conn->sm_engine_state = SM_GENERAL_IDLE;
}{ ... }
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
static void sm_event_handle_classic_encryption_event(sm_connection_t * sm_conn, hci_con_handle_t con_handle){
if (sm_conn->sm_connection_encrypted != 2) return;
if (IS_RESPONDER(sm_conn->sm_role)){
sm_conn->sm_engine_state = SM_BR_EDR_RESPONDER_W4_PAIRING_REQUEST;
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else if (sm_conn->sm_pairing_requested){
bool defer = true;
const hci_connection_t * hci_connection = hci_connection_for_handle(con_handle);
if (hci_connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_DONE){
if ((hci_connection->l2cap_state.fixed_channels_supported & (1 << L2CAP_CID_BR_EDR_SECURITY_MANAGER)) != 0){
log_info("CTKD: SM_BR_EDR_INITIATOR_SEND_PAIRING_REQUEST");
sm_conn->sm_engine_state = SM_BR_EDR_INITIATOR_SEND_PAIRING_REQUEST;
}if ((hci_connection->l2cap_state.fixed_channels_supported & (1 << L2CAP_CID_BR_EDR_SECURITY_MANAGER)) != 0) { ... } else {
defer = false;
}else { ... }
}if (hci_connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_DONE) { ... } else {
log_info("CTKD: SM_BR_EDR_INITIATOR_W4_FIXED_CHANNEL_MASK");
sm_conn->sm_engine_state = SM_BR_EDR_INITIATOR_W4_FIXED_CHANNEL_MASK;
}else { ... }
if (defer){
hci_dedicated_bonding_defer_disconnect(con_handle, true);
}if (defer) { ... }
}else if (sm_conn->sm_pairing_requested) { ... }
}sm_event_handle_classic_encryption_event (sm_connection_t * sm_conn, hci_con_handle_t con_handle) { ... }
/* ... */#endif
static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
sm_connection_t * sm_conn;
hci_con_handle_t con_handle;
uint8_t status;
bd_addr_t addr;
bd_addr_type_t addr_type;
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)) {
case BTSTACK_EVENT_STATE:
switch (btstack_event_state_get_state(packet)){
case HCI_STATE_WORKING:
log_info("HCI Working!");
btstack_tlv_get_instance(&sm_tlv_impl, &sm_tlv_context);
if (sm_tlv_impl != NULL){
int key_size = sm_tlv_impl->get_tag(sm_tlv_context, BTSTACK_TAG32('S','M','E','R'), sm_persistent_er, 16u);
if (key_size == 16){
log_info("ER from TLV");
sm_handle_random_result_er( NULL );
}if (key_size == 16) { ... } else {
sm_persistent_keys_random_active = true;
btstack_crypto_random_generate(&sm_crypto_random_request, sm_persistent_er, 16, &sm_handle_random_result_er, &sm_persistent_er);
}else { ... }
}if (sm_tlv_impl != NULL) { ... } else {
sm_validate_er_ir();
dkg_state = DKG_CALC_IRK;
if (test_use_fixed_local_irk){
log_info_key("IRK", sm_persistent_irk);
dkg_state = DKG_CALC_DHK;
}if (test_use_fixed_local_irk) { ... }
}else { ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (ec_key_generation_state == EC_KEY_GENERATION_IDLE){
sm_ec_generate_new_key();
}if (ec_key_generation_state == EC_KEY_GENERATION_IDLE) { ... }
/* ... */#endif
if (gap_random_adress_type == GAP_RANDOM_ADDRESS_TYPE_STATIC){
gap_random_address_set(sm_random_address);
}if (gap_random_adress_type == GAP_RANDOM_ADDRESS_TYPE_STATIC) { ... } else {
gap_random_address_set_mode(gap_random_adress_type);
}else { ... }
break;
case HCI_STATE_WORKING:
case HCI_STATE_OFF:
case HCI_STATE_HALTING:
log_info("SM: reset state");
gap_random_address_update_stop();
sm_state_reset();
break;
case HCI_STATE_HALTING:
default:
break;default
}switch (btstack_event_state_get_state(packet)) { ... }
break;
#ifdef ENABLE_CLASSICcase BTSTACK_EVENT_STATE:
case HCI_EVENT_CONNECTION_COMPLETE:
if (hci_event_connection_complete_get_status(packet)) return;
con_handle = hci_event_connection_complete_get_connection_handle(packet);
sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) break;
hci_event_connection_complete_get_bd_addr(packet, addr);
sm_connection_init(sm_conn,
con_handle,
(uint8_t) gap_get_role(con_handle),
BD_ADDR_TYPE_LE_PUBLIC,
addr);
sm_conn->sm_own_addr_type = BD_ADDR_TYPE_LE_PUBLIC;
gap_local_bd_addr(sm_conn->sm_own_address);
sm_conn->sm_cid = L2CAP_CID_BR_EDR_SECURITY_MANAGER;
sm_conn->sm_engine_state = SM_BR_EDR_W4_ENCRYPTION_COMPLETE;
break;/* ... */
#endif
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATIONcase HCI_EVENT_CONNECTION_COMPLETE:
case HCI_EVENT_SIMPLE_PAIRING_COMPLETE:
if (hci_event_simple_pairing_complete_get_status(packet) != ERROR_CODE_SUCCESS) break;
hci_event_simple_pairing_complete_get_bd_addr(packet, addr);
sm_conn = sm_get_connection_for_bd_addr_and_type(addr, BD_ADDR_TYPE_ACL);
if (sm_conn == NULL) break;
sm_conn->sm_pairing_requested = true;
break;/* ... */
#endif
case HCI_EVENT_SIMPLE_PAIRING_COMPLETE:
case HCI_EVENT_META_GAP:
switch (hci_event_gap_meta_get_subevent_code(packet)) {
case GAP_SUBEVENT_LE_CONNECTION_COMPLETE:
if (gap_subevent_le_connection_complete_get_status(packet) != ERROR_CODE_SUCCESS) break;
con_handle = gap_subevent_le_connection_complete_get_connection_handle(packet);
sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) break;
addr_type = gap_subevent_le_connection_complete_get_peer_address_type(packet);
if (hci_is_le_identity_address_type(addr_type)){
addr_type = BD_ADDR_TYPE_LE_RANDOM;
gap_subevent_le_connection_complete_get_peer_resolvable_private_address(packet, addr);
}if (hci_is_le_identity_address_type(addr_type)) { ... } else {
gap_subevent_le_connection_complete_get_peer_address(packet, addr);
}else { ... }
sm_connection_init(sm_conn,
con_handle,
gap_subevent_le_connection_complete_get_role(packet),
addr_type,
addr);
sm_conn->sm_cid = L2CAP_CID_SECURITY_MANAGER_PROTOCOL;
#ifdef ENABLE_LE_PERIPHERAL
if (gap_subevent_le_connection_complete_get_role(packet) != 0){
#ifdef ENABLE_LE_EXTENDED_ADVERTISING
if (hci_le_extended_advertising_supported()){
sm_conn->sm_own_addr_type = BD_ADDR_TYPE_LE_RANDOM;
gap_subevent_le_connection_complete_get_local_resolvable_private_address(packet,sm_conn->sm_own_address);
}if (hci_le_extended_advertising_supported()) { ... } else
#endif
{
gap_le_get_own_advertisements_address(&sm_conn->sm_own_addr_type, sm_conn->sm_own_address);
}else { ... }
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
}if (gap_subevent_le_connection_complete_get_role(packet) != 0) { ... }
/* ... */#endif
#ifdef ENABLE_LE_CENTRAL
if (gap_subevent_le_connection_complete_get_role(packet) == 0){
gap_le_get_own_connection_address(&sm_conn->sm_own_addr_type, sm_conn->sm_own_address);
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
}if (gap_subevent_le_connection_complete_get_role(packet) == 0) { ... }
/* ... */#endif
break;case GAP_SUBEVENT_LE_CONNECTION_COMPLETE:
default:
break;default
}switch (hci_event_gap_meta_get_subevent_code(packet)) { ... }
break;case HCI_EVENT_META_GAP:
case HCI_EVENT_LE_META:
switch (hci_event_le_meta_get_subevent_code(packet)) {
#ifdef ENABLE_LE_PERIPHERAL
#ifdef ENABLE_LE_EXTENDED_ADVERTISING
case HCI_SUBEVENT_LE_ADVERTISING_SET_TERMINATED:
if (hci_subevent_le_advertising_set_terminated_get_status(packet) == ERROR_CODE_SUCCESS){
uint8_t advertising_handle = hci_subevent_le_advertising_set_terminated_get_advertising_handle(packet);
con_handle = hci_subevent_le_advertising_set_terminated_get_connection_handle(packet);
sm_conn = sm_get_connection_for_handle(con_handle);
gap_le_get_own_advertising_set_address(&sm_conn->sm_own_addr_type, sm_conn->sm_own_address, advertising_handle);
log_info("Adv set %u terminated -> use addr type %u, addr %s for con handle 0x%04x", advertising_handle, sm_conn->sm_own_addr_type,
bd_addr_to_str(sm_conn->sm_own_address), con_handle);
}if (hci_subevent_le_advertising_set_terminated_get_status(packet) == ERROR_CODE_SUCCESS) { ... }
break;/* ... */
#endif/* ... */
#endif
case HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST:
con_handle = hci_subevent_le_long_term_key_request_get_connection_handle(packet);
sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) break;
log_info("LTK Request: state %u", sm_conn->sm_engine_state);
if (sm_conn->sm_engine_state == SM_RESPONDER_PH2_W4_LTK_REQUEST){
sm_conn->sm_engine_state = SM_PH2_CALC_STK;
break;
}if (sm_conn->sm_engine_state == SM_RESPONDER_PH2_W4_LTK_REQUEST) { ... }
if (sm_conn->sm_engine_state == SM_SC_W4_LTK_REQUEST_SC){
sm_conn->sm_engine_state = SM_RESPONDER_PH2_SEND_LTK_REPLY;
break;
}if (sm_conn->sm_engine_state == SM_SC_W4_LTK_REQUEST_SC) { ... }
reverse_64(&packet[5], sm_conn->sm_local_rand);
sm_conn->sm_local_ediv = hci_subevent_le_long_term_key_request_get_encryption_diversifier(packet);
if ((sm_conn->sm_local_ediv != 0u) || !sm_is_null_random(sm_conn->sm_local_rand)){
if (sm_reconstruct_ltk_without_le_device_db_entry){
sm_conn->sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST;
break;
}if (sm_reconstruct_ltk_without_le_device_db_entry) { ... }
switch(sm_conn->sm_irk_lookup_state){
case IRK_LOOKUP_FAILED:
log_info("LTK Request: device not in device db");
sm_conn->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
break;case IRK_LOOKUP_FAILED:
case IRK_LOOKUP_SUCCEEDED:
sm_conn->sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK_REQUEST;
break;case IRK_LOOKUP_SUCCEEDED:
default:
sm_conn->sm_engine_state = SM_RESPONDER_PH0_RECEIVED_LTK_W4_IRK;
break;default
}switch (sm_conn->sm_irk_lookup_state) { ... }
break;
}if ((sm_conn->sm_local_ediv != 0u) || !sm_is_null_random(sm_conn->sm_local_rand)) { ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
sm_conn->sm_engine_state = SM_SC_RECEIVED_LTK_REQUEST;
#else
log_info("LTK Request: ediv & random are empty, but LE Secure Connections not supported");
sm_conn->sm_engine_state = SM_RESPONDER_PH0_SEND_LTK_REQUESTED_NEGATIVE_REPLY;/* ... */
#endif
break;
case HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST:
default:
break;default
}switch (hci_event_le_meta_get_subevent_code(packet)) { ... }
break;
case HCI_EVENT_LE_META:
case HCI_EVENT_ENCRYPTION_CHANGE:
case HCI_EVENT_ENCRYPTION_CHANGE_V2:
con_handle = hci_event_encryption_change_get_connection_handle(packet);
sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) break;
sm_conn->sm_connection_encrypted = hci_event_encryption_change_get_encryption_enabled(packet);
log_info("Encryption state change: %u, key size %u", sm_conn->sm_connection_encrypted,
sm_conn->sm_actual_encryption_key_size);
log_info("event handler, state %u", sm_conn->sm_engine_state);
switch (sm_conn->sm_engine_state){
case SM_PH4_W4_CONNECTION_ENCRYPTED:
if (sm_conn->sm_connection_encrypted != 0u) {
status = ERROR_CODE_SUCCESS;
if (IS_RESPONDER(sm_conn->sm_role)){
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
}else { ... }
}if (sm_conn->sm_connection_encrypted != 0u) { ... } else {
status = hci_event_encryption_change_get_status(packet);
sm_conn->sm_engine_state = SM_GENERAL_REENCRYPTION_FAILED;
}else { ... }
sm_reencryption_complete(sm_conn, status);
if (sm_conn->sm_pairing_requested){
sm_conn->sm_pairing_requested = false;
sm_pairing_complete(sm_conn, status, 0);
}if (sm_conn->sm_pairing_requested) { ... }
sm_done_for_handle(sm_conn->sm_handle);
break;
case SM_PH4_W4_CONNECTION_ENCRYPTED:
case SM_PH2_W4_CONNECTION_ENCRYPTED:
if (!sm_conn->sm_connection_encrypted) break;
sm_conn->sm_connection_sc = setup->sm_use_secure_connections;
if (IS_RESPONDER(sm_conn->sm_role)){
if (sm_conn->sm_connection_sc){
sm_conn->sm_engine_state = SM_PH3_DISTRIBUTE_KEYS;
}if (sm_conn->sm_connection_sc) { ... } else {
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_data, 8, &sm_handle_random_result_ph3_random, (void *)(uintptr_t) sm_conn->sm_handle);
}else { ... }
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
if (sm_key_distribution_all_received()){
sm_key_distribution_handle_all_received(sm_conn);
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_data, 8, &sm_handle_random_result_ph3_random, (void *)(uintptr_t) sm_conn->sm_handle);
}if (sm_key_distribution_all_received()) { ... } else {
sm_conn->sm_engine_state = SM_PH3_RECEIVE_KEYS;
}else { ... }
}else { ... }
break;
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATIONcase SM_PH2_W4_CONNECTION_ENCRYPTED:
case SM_BR_EDR_W4_ENCRYPTION_COMPLETE:
sm_event_handle_classic_encryption_event(sm_conn, con_handle);
break;/* ... */
#endifcase SM_BR_EDR_W4_ENCRYPTION_COMPLETE:
default:
break;default
}switch (sm_conn->sm_engine_state) { ... }
break;
case HCI_EVENT_ENCRYPTION_CHANGE_V2:
case HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE:
con_handle = little_endian_read_16(packet, 3);
sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) break;
log_info("Encryption key refresh complete, key size %u", sm_conn->sm_actual_encryption_key_size);
log_info("event handler, state %u", sm_conn->sm_engine_state);
switch (sm_conn->sm_engine_state){
case SM_PH4_W4_CONNECTION_ENCRYPTED:
if (IS_RESPONDER(sm_conn->sm_role)){
sm_conn->sm_engine_state = SM_RESPONDER_IDLE;
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
}else { ... }
sm_done_for_handle(sm_conn->sm_handle);
break;case SM_PH4_W4_CONNECTION_ENCRYPTED:
case SM_PH2_W4_CONNECTION_ENCRYPTED:
sm_conn->sm_connection_sc = setup->sm_use_secure_connections;
if (IS_RESPONDER(sm_conn->sm_role)){
if (sm_conn->sm_connection_sc){
sm_conn->sm_engine_state = SM_PH3_DISTRIBUTE_KEYS;
}if (sm_conn->sm_connection_sc) { ... } else {
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_data, 8, &sm_handle_random_result_ph3_random, (void *)(uintptr_t) sm_conn->sm_handle);
}else { ... }
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
if (sm_key_distribution_all_received()){
sm_key_distribution_handle_all_received(sm_conn);
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_data, 8, &sm_handle_random_result_ph3_random, (void *)(uintptr_t) sm_conn->sm_handle);
}if (sm_key_distribution_all_received()) { ... } else {
sm_conn->sm_engine_state = SM_PH3_RECEIVE_KEYS;
}else { ... }
}else { ... }
break;
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATIONcase SM_PH2_W4_CONNECTION_ENCRYPTED:
case SM_BR_EDR_W4_ENCRYPTION_COMPLETE:
sm_event_handle_classic_encryption_event(sm_conn, con_handle);
break;/* ... */
#endifcase SM_BR_EDR_W4_ENCRYPTION_COMPLETE:
default:
break;default
}switch (sm_conn->sm_engine_state) { ... }
break;
case HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE:
case HCI_EVENT_DISCONNECTION_COMPLETE:
con_handle = little_endian_read_16(packet, 3);
sm_done_for_handle(con_handle);
sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) break;
switch (sm_conn->sm_engine_state){
case SM_GENERAL_IDLE:
case SM_INITIATOR_CONNECTED:
case SM_RESPONDER_IDLE:
break;case SM_RESPONDER_IDLE:
default:
sm_reencryption_complete(sm_conn, ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION);
sm_pairing_complete(sm_conn, ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION, 0);
break;default
}switch (sm_conn->sm_engine_state) { ... }
sm_conn->sm_engine_state = SM_GENERAL_IDLE;
sm_conn->sm_handle = 0;
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
case HCI_EVENT_COMMAND_COMPLETE:
if (hci_event_command_complete_get_command_opcode(packet) == HCI_OPCODE_HCI_READ_BD_ADDR) {
reverse_bd_addr(&packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE + 1], addr);
le_device_db_set_local_bd_addr(addr);
}if (hci_event_command_complete_get_command_opcode(packet) == HCI_OPCODE_HCI_READ_BD_ADDR) { ... }
break;
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATIONcase HCI_EVENT_COMMAND_COMPLETE:
case L2CAP_EVENT_INFORMATION_RESPONSE:
con_handle = l2cap_event_information_response_get_con_handle(packet);
sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) break;
if (sm_conn->sm_engine_state == SM_BR_EDR_INITIATOR_W4_FIXED_CHANNEL_MASK){
const hci_connection_t * hci_connection = hci_connection_for_handle(con_handle);
if ((hci_connection->l2cap_state.fixed_channels_supported & (1 << L2CAP_CID_BR_EDR_SECURITY_MANAGER)) != 0){
sm_conn->sm_engine_state = SM_BR_EDR_INITIATOR_SEND_PAIRING_REQUEST;
}if ((hci_connection->l2cap_state.fixed_channels_supported & (1 << L2CAP_CID_BR_EDR_SECURITY_MANAGER)) != 0) { ... } else {
sm_conn->sm_engine_state = SM_INITIATOR_CONNECTED;
hci_dedicated_bonding_defer_disconnect(con_handle, false);
}else { ... }
}if (sm_conn->sm_engine_state == SM_BR_EDR_INITIATOR_W4_FIXED_CHANNEL_MASK) { ... }
break;/* ... */
#endifcase L2CAP_EVENT_INFORMATION_RESPONSE:
default:
break;default
}switch (hci_event_packet_get_type(packet)) { ... }
break;case HCI_EVENT_PACKET:
default:
break;default
}switch (packet_type) { ... }
sm_run();
}{ ... }
static inline int sm_calc_actual_encryption_key_size(int other){
if (other < sm_min_encryption_key_size) return 0;
if (other < sm_max_encryption_key_size) return other;
return sm_max_encryption_key_size;
}{ ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static bool sm_just_works_or_numeric_comparison(stk_generation_method_t method){
switch (method){
case JUST_WORKS:
case NUMERIC_COMPARISON:
return true;case NUMERIC_COMPARISON:
default:
return false;default
}switch (method) { ... }
}sm_just_works_or_numeric_comparison (stk_generation_method_t method) { ... }
static bool sm_passkey_used(stk_generation_method_t method){
switch (method){
case PK_RESP_INPUT:
return true;case PK_RESP_INPUT:
default:
return 0;default
}switch (method) { ... }
}sm_passkey_used (stk_generation_method_t method) { ... }
static bool sm_passkey_entry(stk_generation_method_t method){
switch (method){
case PK_RESP_INPUT:
case PK_INIT_INPUT:
case PK_BOTH_INPUT:
return true;case PK_BOTH_INPUT:
default:
return false;default
}switch (method) { ... }
}sm_passkey_entry (stk_generation_method_t method) { ... }
/* ... */
#endif
/* ... */
static int sm_validate_stk_generation_method(void){
switch (setup->sm_stk_generation_method){
case JUST_WORKS:
return (sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_JUST_WORKS) != 0u;case JUST_WORKS:
case PK_RESP_INPUT:
case PK_INIT_INPUT:
case PK_BOTH_INPUT:
return (sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_PASSKEY) != 0u;case PK_BOTH_INPUT:
case OOB:
return (sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_OOB) != 0u;case OOB:
case NUMERIC_COMPARISON:
return (sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_NUMERIC_COMPARISON) != 0u;case NUMERIC_COMPARISON:
default:
return 0;default
}switch (setup->sm_stk_generation_method) { ... }
}{ ... }
#ifdef ENABLE_LE_CENTRAL
static void sm_initiator_connected_handle_security_request(sm_connection_t * sm_conn, const uint8_t *packet){
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (sm_sc_only_mode){
uint8_t auth_req = packet[1];
if ((auth_req & SM_AUTHREQ_SECURE_CONNECTION) == 0){
sm_pairing_error(sm_conn, SM_REASON_AUTHENTHICATION_REQUIREMENTS);
return;
}if ((auth_req & SM_AUTHREQ_SECURE_CONNECTION) == 0) { ... }
}if (sm_sc_only_mode) { ... }
/* ... */#else
UNUSED(packet);
#endif
int have_ltk;
uint8_t ltk[16];
switch (sm_conn->sm_irk_lookup_state){
case IRK_LOOKUP_FAILED:
sm_conn->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
break;case IRK_LOOKUP_FAILED:
case IRK_LOOKUP_SUCCEEDED:
le_device_db_encryption_get(sm_conn->sm_le_db_index, NULL, NULL, ltk, NULL, NULL, NULL, NULL);
have_ltk = !sm_is_null_key(ltk);
log_info("central: security request - have_ltk %u, encryption %u", have_ltk, sm_conn->sm_connection_encrypted);
if (have_ltk && (sm_conn->sm_connection_encrypted == 0)){
sm_conn->sm_engine_state = SM_INITIATOR_PH4_HAS_LTK;
}if (have_ltk && (sm_conn->sm_connection_encrypted == 0)) { ... } else {
sm_conn->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
}else { ... }
break;case IRK_LOOKUP_SUCCEEDED:
default:
sm_conn->sm_security_request_received = true;
break;default
}switch (sm_conn->sm_irk_lookup_state) { ... }
}sm_initiator_connected_handle_security_request (sm_connection_t * sm_conn, const uint8_t *packet) { ... }
/* ... */#endif
static uint8_t sm_pdu_validate_and_get_opcode(uint8_t packet_type, const uint8_t *packet, uint16_t size){
static const uint8_t sm_pdu_size[] = {
0,
7,
7,
17,
17,
2,
17,
11,
17,
8,
17,
2,
65,
17,
2,
...};
if (packet_type != SM_DATA_PACKET) return 0;
if (size == 0u) return 0;
uint8_t sm_pdu_code = packet[0];
if (sm_pdu_code >= sizeof(sm_pdu_size)) return 0;
if (sm_pdu_size[sm_pdu_code] != size) return 0;
return sm_pdu_code;
}{ ... }
static void sm_pdu_handler(sm_connection_t *sm_conn, uint8_t sm_pdu_code, const uint8_t *packet) {
log_debug("sm_pdu_handler: state %u, pdu 0x%02x", sm_conn->sm_engine_state, sm_pdu_code);
int err;
uint8_t max_encryption_key_size;
UNUSED(err);
switch (sm_conn->sm_engine_state){
case SM_GENERAL_TIMEOUT:
return;
#ifdef ENABLE_LE_CENTRAL
case SM_INITIATOR_CONNECTED:
if ((sm_pdu_code != SM_CODE_SECURITY_REQUEST) || (sm_conn->sm_role)){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if ((sm_pdu_code != SM_CODE_SECURITY_REQUEST) || (sm_conn->sm_role)) { ... }
sm_initiator_connected_handle_security_request(sm_conn, packet);
break;
case SM_INITIATOR_CONNECTED:
case SM_INITIATOR_PH1_W4_PAIRING_RESPONSE:
if (sm_pdu_code == SM_CODE_SECURITY_REQUEST){
log_info("Ignoring Security Request");
break;
}if (sm_pdu_code == SM_CODE_SECURITY_REQUEST) { ... }
if (sm_pdu_code != SM_CODE_PAIRING_RESPONSE){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_RESPONSE) { ... }
(void)memcpy(&setup->sm_s_pres, packet,
sizeof(sm_pairing_packet_t));
max_encryption_key_size = sm_pairing_packet_get_max_encryption_key_size(setup->sm_s_pres);
if ((max_encryption_key_size < 7) || (max_encryption_key_size > 16)){
sm_pairing_error(sm_conn, SM_REASON_INVALID_PARAMETERS);
break;
}if ((max_encryption_key_size < 7) || (max_encryption_key_size > 16)) { ... }
err = sm_stk_generation_init(sm_conn);
#ifdef ENABLE_TESTING_SUPPORT
if (0 < test_pairing_failure && test_pairing_failure < SM_REASON_DHKEY_CHECK_FAILED){
log_info("testing_support: abort with pairing failure %u", test_pairing_failure);
err = test_pairing_failure;
}if (0 < test_pairing_failure && test_pairing_failure < SM_REASON_DHKEY_CHECK_FAILED) { ... }
/* ... */#endif
if (err != 0){
sm_pairing_error(sm_conn, err);
break;
}if (err != 0) { ... }
if (setup->sm_stk_generation_method == PK_RESP_INPUT){
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_data, 8, &sm_handle_random_result_ph2_tk, (void *)(uintptr_t) sm_conn->sm_handle);
break;
}if (setup->sm_stk_generation_method == PK_RESP_INPUT) { ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (setup->sm_use_secure_connections){
if (setup->sm_stk_generation_method == JUST_WORKS){
sm_conn->sm_engine_state = SM_PH1_W4_USER_RESPONSE;
sm_trigger_user_response(sm_conn);
if (setup->sm_user_response == SM_USER_RESPONSE_IDLE){
sm_conn->sm_engine_state = SM_SC_SEND_PUBLIC_KEY_COMMAND;
}if (setup->sm_user_response == SM_USER_RESPONSE_IDLE) { ... }
}if (setup->sm_stk_generation_method == JUST_WORKS) { ... } else {
sm_conn->sm_engine_state = SM_SC_SEND_PUBLIC_KEY_COMMAND;
}else { ... }
break;
}if (setup->sm_use_secure_connections) { ... }
/* ... */#endif
sm_conn->sm_engine_state = SM_PH1_W4_USER_RESPONSE;
sm_trigger_user_response(sm_conn);
if (setup->sm_user_response == SM_USER_RESPONSE_IDLE){
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_random, 16, &sm_handle_random_result_ph2_random, (void *)(uintptr_t) sm_conn->sm_handle);
}if (setup->sm_user_response == SM_USER_RESPONSE_IDLE) { ... }
break;
case SM_INITIATOR_PH1_W4_PAIRING_RESPONSE:
case SM_INITIATOR_PH2_W4_PAIRING_CONFIRM:
if (sm_pdu_code != SM_CODE_PAIRING_CONFIRM){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_CONFIRM) { ... }
reverse_128(&packet[1], setup->sm_peer_confirm);
if (memcmp(setup->sm_local_confirm, setup->sm_peer_confirm, 16) == 0){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (memcmp(setup->sm_local_confirm, setup->sm_peer_confirm, 16) == 0) { ... }
#ifdef ENABLE_TESTING_SUPPORT
if (test_pairing_failure == SM_REASON_CONFIRM_VALUE_FAILED){
log_info("testing_support: reset confirm value");
memset(setup->sm_peer_confirm, 0, 16);
}if (test_pairing_failure == SM_REASON_CONFIRM_VALUE_FAILED) { ... }
/* ... */#endif
sm_conn->sm_engine_state = SM_PH2_SEND_PAIRING_RANDOM;
break;
case SM_INITIATOR_PH2_W4_PAIRING_CONFIRM:
case SM_INITIATOR_PH2_W4_PAIRING_RANDOM:
if (sm_pdu_code != SM_CODE_PAIRING_RANDOM){
sm_pdu_received_in_wrong_state(sm_conn);
break;;
}if (sm_pdu_code != SM_CODE_PAIRING_RANDOM) { ... }
reverse_128(&packet[1], setup->sm_peer_random);
sm_conn->sm_engine_state = SM_PH2_C1_GET_ENC_C;
break;
case SM_INITIATOR_PH2_W4_PAIRING_RANDOM:
case SM_INITIATOR_PH4_HAS_LTK:
case SM_PH4_W4_CONNECTION_ENCRYPTED:
if (sm_pdu_code != SM_CODE_SECURITY_REQUEST){
sm_pdu_received_in_wrong_state(sm_conn);
}if (sm_pdu_code != SM_CODE_SECURITY_REQUEST) { ... }
break;/* ... */
#endif
#ifdef ENABLE_LE_PERIPHERAL
case SM_RESPONDER_IDLE:
case SM_RESPONDER_SEND_SECURITY_REQUEST:
case SM_RESPONDER_PH1_W4_PAIRING_REQUEST:
if (sm_pdu_code != SM_CODE_PAIRING_REQUEST){
sm_pdu_received_in_wrong_state(sm_conn);
break;;
}if (sm_pdu_code != SM_CODE_PAIRING_REQUEST) { ... }
(void)memcpy(&sm_conn->sm_m_preq, packet, sizeof(sm_pairing_packet_t));
max_encryption_key_size = sm_pairing_packet_get_max_encryption_key_size(sm_conn->sm_m_preq);
if ((max_encryption_key_size < 7) || (max_encryption_key_size > 16)){
sm_pairing_error(sm_conn, SM_REASON_INVALID_PARAMETERS);
break;
}if ((max_encryption_key_size < 7) || (max_encryption_key_size > 16)) { ... }
switch (sm_conn->sm_irk_lookup_state){
case IRK_LOOKUP_SUCCEEDED:
case IRK_LOOKUP_FAILED:
sm_conn->sm_engine_state = SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED;
break;case IRK_LOOKUP_FAILED:
default:
sm_conn->sm_engine_state = SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED_W4_IRK;
break;default
}switch (sm_conn->sm_irk_lookup_state) { ... }
break;/* ... */
#endif
#ifdef ENABLE_LE_SECURE_CONNECTIONS
case SM_SC_W4_PUBLIC_KEY_COMMAND:
if (sm_pdu_code != SM_CODE_PAIRING_PUBLIC_KEY){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_PUBLIC_KEY) { ... }
reverse_256(&packet[01], &setup->sm_peer_q[0]);
reverse_256(&packet[33], &setup->sm_peer_q[32]);
if (memcmp(&setup->sm_peer_q, ec_q, 64) == 0){
log_info("Remote PK matches ours");
sm_pairing_error(sm_conn, SM_REASON_DHKEY_CHECK_FAILED);
break;
}if (memcmp(&setup->sm_peer_q, ec_q, 64) == 0) { ... }
err = btstack_crypto_ecc_p256_validate_public_key(setup->sm_peer_q);
if (err != 0){
log_info("sm: peer public key invalid %x", err);
sm_pairing_error(sm_conn, SM_REASON_DHKEY_CHECK_FAILED);
break;
}if (err != 0) { ... }
btstack_crypto_ecc_p256_calculate_dhkey(&sm_crypto_ecc_p256_request, setup->sm_peer_q, setup->sm_dhkey, sm_sc_dhkey_calculated, (void*)(uintptr_t) sm_conn->sm_handle);
log_info("public key received, generation method %u", setup->sm_stk_generation_method);
if (IS_RESPONDER(sm_conn->sm_role)){
sm_conn->sm_engine_state = SM_SC_SEND_PUBLIC_KEY_COMMAND;
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
switch (setup->sm_stk_generation_method){
case JUST_WORKS:
case NUMERIC_COMPARISON:
sm_conn->sm_engine_state = SM_SC_W4_CONFIRMATION;
break;case NUMERIC_COMPARISON:
case PK_RESP_INPUT:
sm_sc_start_calculating_local_confirm(sm_conn);
break;case PK_RESP_INPUT:
case PK_INIT_INPUT:
case PK_BOTH_INPUT:
if (setup->sm_user_response != SM_USER_RESPONSE_PASSKEY){
sm_conn->sm_engine_state = SM_SC_W4_USER_RESPONSE;
break;
}if (setup->sm_user_response != SM_USER_RESPONSE_PASSKEY) { ... }
sm_sc_start_calculating_local_confirm(sm_conn);
break;case PK_BOTH_INPUT:
case OOB:
log_info("Generate Na");
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_nonce, 16, &sm_handle_random_result_sc_next_send_pairing_random, (void*)(uintptr_t) sm_conn->sm_handle);
break;case OOB:
default:
btstack_assert(false);
break;default
}switch (setup->sm_stk_generation_method) { ... }
}else { ... }
break;
case SM_SC_W4_PUBLIC_KEY_COMMAND:
case SM_SC_W4_CONFIRMATION:
if (sm_pdu_code != SM_CODE_PAIRING_CONFIRM){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_CONFIRM) { ... }
reverse_128(&packet[1], setup->sm_peer_confirm);
#ifdef ENABLE_TESTING_SUPPORT
if (test_pairing_failure == SM_REASON_CONFIRM_VALUE_FAILED){
log_info("testing_support: reset confirm value");
memset(setup->sm_peer_confirm, 0, 16);
}if (test_pairing_failure == SM_REASON_CONFIRM_VALUE_FAILED) { ... }
/* ... */#endif
if (IS_RESPONDER(sm_conn->sm_role)){
if (sm_passkey_used(setup->sm_stk_generation_method)){
if (setup->sm_user_response != SM_USER_RESPONSE_PASSKEY){
sm_conn->sm_engine_state = SM_SC_W4_USER_RESPONSE;
break;
}if (setup->sm_user_response != SM_USER_RESPONSE_PASSKEY) { ... }
}if (sm_passkey_used(setup->sm_stk_generation_method)) { ... }
sm_sc_start_calculating_local_confirm(sm_conn);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
if (sm_just_works_or_numeric_comparison(setup->sm_stk_generation_method)){
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_nonce, 16, &sm_handle_random_result_sc_next_send_pairing_random, (void*)(uintptr_t) sm_conn->sm_handle);
}if (sm_just_works_or_numeric_comparison(setup->sm_stk_generation_method)) { ... } else {
sm_conn->sm_engine_state = SM_SC_SEND_PAIRING_RANDOM;
}else { ... }
}else { ... }
break;
case SM_SC_W4_CONFIRMATION:
case SM_SC_W4_PAIRING_RANDOM:
if (sm_pdu_code != SM_CODE_PAIRING_RANDOM){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_RANDOM) { ... }
reverse_128(&packet[1], setup->sm_peer_nonce);
log_info("SM_SC_W4_PAIRING_RANDOM, responder: %u, just works: %u, passkey used %u, passkey entry %u",
IS_RESPONDER(sm_conn->sm_role), sm_just_works_or_numeric_comparison(setup->sm_stk_generation_method),
sm_passkey_used(setup->sm_stk_generation_method), sm_passkey_entry(setup->sm_stk_generation_method));
if ( (!IS_RESPONDER(sm_conn->sm_role) && sm_just_works_or_numeric_comparison(setup->sm_stk_generation_method))
|| (sm_passkey_entry(setup->sm_stk_generation_method)) ) {
sm_conn->sm_engine_state = SM_SC_W2_CMAC_FOR_CHECK_CONFIRMATION;
break;
}if ((!IS_RESPONDER(sm_conn->sm_role) && sm_just_works_or_numeric_comparison(setup->sm_stk_generation_method)) || (sm_passkey_entry(setup->sm_stk_generation_method))) { ... }
if (setup->sm_stk_generation_method == OOB){
log_info("Received nonce, setup local random ra/rb for dhkey check");
if (IS_RESPONDER(sm_conn->sm_role)){
if (sm_pairing_packet_get_oob_data_flag(setup->sm_m_preq) == 0u){
log_info("Reset rb as A does not have OOB data");
memset(setup->sm_rb, 0, 16);
}if (sm_pairing_packet_get_oob_data_flag(setup->sm_m_preq) == 0u) { ... } else {
(void)memcpy(setup->sm_rb, sm_sc_oob_random, 16);
log_info("Use stored rb");
log_info_hexdump(setup->sm_rb, 16);
}else { ... }
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
if (sm_pairing_packet_get_oob_data_flag(setup->sm_s_pres) == 0u){
log_info("Reset ra as B does not have OOB data");
memset(setup->sm_ra, 0, 16);
}if (sm_pairing_packet_get_oob_data_flag(setup->sm_s_pres) == 0u) { ... } else {
(void)memcpy(setup->sm_ra, sm_sc_oob_random, 16);
log_info("Use stored ra");
log_info_hexdump(setup->sm_ra, 16);
}else { ... }
}else { ... }
if (setup->sm_have_oob_data){
sm_conn->sm_engine_state = SM_SC_W2_CMAC_FOR_CHECK_CONFIRMATION;
break;
}if (setup->sm_have_oob_data) { ... }
}if (setup->sm_stk_generation_method == OOB) { ... }
sm_sc_state_after_receiving_random(sm_conn);
break;
case SM_SC_W4_PAIRING_RANDOM:
case SM_SC_W2_CALCULATE_G2:
case SM_SC_W4_CALCULATE_G2:
case SM_SC_W4_CALCULATE_DHKEY:
case SM_SC_W2_CALCULATE_F5_SALT:
case SM_SC_W4_CALCULATE_F5_SALT:
case SM_SC_W2_CALCULATE_F5_MACKEY:
case SM_SC_W4_CALCULATE_F5_MACKEY:
case SM_SC_W2_CALCULATE_F5_LTK:
case SM_SC_W4_CALCULATE_F5_LTK:
case SM_SC_W2_CALCULATE_F6_FOR_DHKEY_CHECK:
case SM_SC_W4_DHKEY_CHECK_COMMAND:
case SM_SC_W4_CALCULATE_F6_FOR_DHKEY_CHECK:
case SM_SC_W4_USER_RESPONSE:
if (sm_pdu_code != SM_CODE_PAIRING_DHKEY_CHECK){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_DHKEY_CHECK) { ... }
setup->sm_state_vars |= SM_STATE_VAR_DHKEY_COMMAND_RECEIVED;
reverse_128(&packet[01], setup->sm_peer_dhkey_check);
if (sm_conn->sm_engine_state == SM_SC_W4_DHKEY_CHECK_COMMAND){
sm_conn->sm_engine_state = SM_SC_W2_CALCULATE_F6_TO_VERIFY_DHKEY_CHECK;
}if (sm_conn->sm_engine_state == SM_SC_W4_DHKEY_CHECK_COMMAND) { ... }
break;/* ... */
#endif
#ifdef ENABLE_LE_PERIPHERAL
case SM_RESPONDER_PH1_W4_PAIRING_CONFIRM:
if (sm_pdu_code != SM_CODE_PAIRING_CONFIRM){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_CONFIRM) { ... }
reverse_128(&packet[1], setup->sm_peer_confirm);
#ifdef ENABLE_TESTING_SUPPORT
if (test_pairing_failure == SM_REASON_CONFIRM_VALUE_FAILED){
log_info("testing_support: reset confirm value");
memset(setup->sm_peer_confirm, 0, 16);
}if (test_pairing_failure == SM_REASON_CONFIRM_VALUE_FAILED) { ... }
/* ... */#endif
if (setup->sm_stk_generation_method == PK_INIT_INPUT){
sm_notify_client_base(SM_EVENT_PASSKEY_DISPLAY_CANCEL, sm_conn->sm_handle, sm_conn->sm_peer_addr_type, sm_conn->sm_peer_address);
}if (setup->sm_stk_generation_method == PK_INIT_INPUT) { ... }
if (setup->sm_user_response == SM_USER_RESPONSE_DECLINE){
sm_pairing_error(sm_conn, SM_REASON_PASSKEY_ENTRY_FAILED);
break;
}if (setup->sm_user_response == SM_USER_RESPONSE_DECLINE) { ... }
if (setup->sm_user_response == SM_USER_RESPONSE_PENDING){
sm_conn->sm_engine_state = SM_PH1_W4_USER_RESPONSE;
break;
}if (setup->sm_user_response == SM_USER_RESPONSE_PENDING) { ... }
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_random, 16, &sm_handle_random_result_ph2_random, (void *)(uintptr_t) sm_conn->sm_handle);
break;
case SM_RESPONDER_PH1_W4_PAIRING_CONFIRM:
case SM_RESPONDER_PH2_W4_PAIRING_RANDOM:
if (sm_pdu_code != SM_CODE_PAIRING_RANDOM){
sm_pdu_received_in_wrong_state(sm_conn);
break;;
}if (sm_pdu_code != SM_CODE_PAIRING_RANDOM) { ... }
reverse_128(&packet[1], setup->sm_peer_random);
sm_conn->sm_engine_state = SM_PH2_C1_GET_ENC_C;
break;/* ... */
#endif
case SM_PH2_W4_CONNECTION_ENCRYPTED:
case SM_PH3_RECEIVE_KEYS:
switch(sm_pdu_code){
case SM_CODE_ENCRYPTION_INFORMATION:
setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION;
reverse_128(&packet[1], setup->sm_peer_ltk);
break;
case SM_CODE_ENCRYPTION_INFORMATION:
case SM_CODE_MASTER_IDENTIFICATION:
setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_MASTER_IDENTIFICATION;
setup->sm_peer_ediv = little_endian_read_16(packet, 1);
reverse_64(&packet[3], setup->sm_peer_rand);
break;
case SM_CODE_MASTER_IDENTIFICATION:
case SM_CODE_IDENTITY_INFORMATION:
setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_IDENTITY_INFORMATION;
reverse_128(&packet[1], setup->sm_peer_irk);
break;
case SM_CODE_IDENTITY_INFORMATION:
case SM_CODE_IDENTITY_ADDRESS_INFORMATION:
setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION;
setup->sm_peer_addr_type = packet[1];
reverse_bd_addr(&packet[2], setup->sm_peer_address);
break;
case SM_CODE_IDENTITY_ADDRESS_INFORMATION:
case SM_CODE_SIGNING_INFORMATION:
setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION;
reverse_128(&packet[1], setup->sm_peer_csrk);
break;case SM_CODE_SIGNING_INFORMATION:
default:
log_info("Unexpected PDU %u in SM_PH3_RECEIVE_KEYS", packet[0]);
break;default
}switch (sm_pdu_code) { ... }
if (sm_key_distribution_all_received()){
sm_key_distribution_handle_all_received(sm_conn);
if (IS_RESPONDER(sm_conn->sm_role)){
sm_key_distribution_complete_responder(sm_conn);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
if (setup->sm_use_secure_connections){
sm_conn->sm_engine_state = SM_PH3_DISTRIBUTE_KEYS;
}if (setup->sm_use_secure_connections) { ... } else {
btstack_crypto_random_generate(&sm_crypto_random_request, sm_random_data, 8, &sm_handle_random_result_ph3_random, (void *)(uintptr_t) sm_conn->sm_handle);
}else { ... }
}else { ... }
}if (sm_key_distribution_all_received()) { ... }
break;
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
case SM_BR_EDR_W4_ENCRYPTION_COMPLETE:
if (sm_pdu_code == SM_CODE_PAIRING_REQUEST){
sm_pairing_error(sm_conn, SM_REASON_CROSS_TRANSPORT_KEY_DERIVATION_NOT_ALLOWED);
}if (sm_pdu_code == SM_CODE_PAIRING_REQUEST) { ... }
break;
case SM_BR_EDR_W4_ENCRYPTION_COMPLETE:
case SM_BR_EDR_INITIATOR_W4_PAIRING_RESPONSE:
hci_dedicated_bonding_defer_disconnect(sm_conn->sm_handle, false);
if (sm_pdu_code != SM_CODE_PAIRING_RESPONSE){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_RESPONSE) { ... }
(void)memcpy(&setup->sm_s_pres, packet, sizeof(sm_pairing_packet_t));
max_encryption_key_size = sm_pairing_packet_get_max_encryption_key_size(setup->sm_s_pres);
if ((max_encryption_key_size < 7) || (max_encryption_key_size > 16)){
sm_pairing_error(sm_conn, SM_REASON_INVALID_PARAMETERS);
break;
}if ((max_encryption_key_size < 7) || (max_encryption_key_size > 16)) { ... }
sm_conn->sm_actual_encryption_key_size = sm_calc_actual_encryption_key_size(max_encryption_key_size);
if (sm_sc_only_mode && (sm_conn->sm_actual_encryption_key_size < 16)) {
sm_conn->sm_actual_encryption_key_size = 0;
}if (sm_sc_only_mode && (sm_conn->sm_actual_encryption_key_size < 16)) { ... }
if (sm_conn->sm_actual_encryption_key_size == 0){
sm_pairing_error(sm_conn, SM_REASON_ENCRYPTION_KEY_SIZE);
break;
}if (sm_conn->sm_actual_encryption_key_size == 0) { ... }
sm_setup_key_distribution(sm_pairing_packet_get_initiator_key_distribution(setup->sm_s_pres) & ~SM_KEYDIST_ENC_KEY,
sm_pairing_packet_get_responder_key_distribution(setup->sm_s_pres) & ~SM_KEYDIST_ENC_KEY);
if (sm_key_distribution_all_received()){
sm_conn->sm_engine_state = SM_BR_EDR_DISTRIBUTE_KEYS;
}if (sm_key_distribution_all_received()) { ... } else {
sm_conn->sm_engine_state = SM_BR_EDR_RECEIVE_KEYS;
}else { ... }
break;
case SM_BR_EDR_INITIATOR_W4_PAIRING_RESPONSE:
case SM_BR_EDR_RESPONDER_W4_PAIRING_REQUEST:
if (sm_pdu_code != SM_CODE_PAIRING_REQUEST){
sm_pdu_received_in_wrong_state(sm_conn);
break;
}if (sm_pdu_code != SM_CODE_PAIRING_REQUEST) { ... }
(void)memcpy(&sm_conn->sm_m_preq, packet, sizeof(sm_pairing_packet_t));
max_encryption_key_size = sm_pairing_packet_get_max_encryption_key_size(sm_conn->sm_m_preq);
if ((max_encryption_key_size < 7) || (max_encryption_key_size > 16)){
sm_pairing_error(sm_conn, SM_REASON_INVALID_PARAMETERS);
break;
}if ((max_encryption_key_size < 7) || (max_encryption_key_size > 16)) { ... }
sm_conn->sm_actual_encryption_key_size = sm_calc_actual_encryption_key_size(max_encryption_key_size);
if (sm_sc_only_mode && (sm_conn->sm_actual_encryption_key_size < 16)) {
sm_conn->sm_actual_encryption_key_size = 0;
}if (sm_sc_only_mode && (sm_conn->sm_actual_encryption_key_size < 16)) { ... }
if (sm_conn->sm_actual_encryption_key_size == 0){
sm_pairing_error(sm_conn, SM_REASON_ENCRYPTION_KEY_SIZE);
break;
}if (sm_conn->sm_actual_encryption_key_size == 0) { ... }
if (sm_ctkd_from_classic(sm_conn)){
sm_conn->sm_engine_state = SM_BR_EDR_RESPONDER_PAIRING_REQUEST_RECEIVED;
}if (sm_ctkd_from_classic(sm_conn)) { ... } else {
sm_pairing_error(sm_conn, SM_REASON_CROSS_TRANSPORT_KEY_DERIVATION_NOT_ALLOWED);
}else { ... }
break;
case SM_BR_EDR_RESPONDER_W4_PAIRING_REQUEST:
case SM_BR_EDR_RECEIVE_KEYS:
switch(sm_pdu_code){
case SM_CODE_IDENTITY_INFORMATION:
setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_IDENTITY_INFORMATION;
reverse_128(&packet[1], setup->sm_peer_irk);
break;case SM_CODE_IDENTITY_INFORMATION:
case SM_CODE_IDENTITY_ADDRESS_INFORMATION:
setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION;
setup->sm_peer_addr_type = packet[1];
reverse_bd_addr(&packet[2], setup->sm_peer_address);
break;case SM_CODE_IDENTITY_ADDRESS_INFORMATION:
case SM_CODE_SIGNING_INFORMATION:
setup->sm_key_distribution_received_set |= SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION;
reverse_128(&packet[1], setup->sm_peer_csrk);
break;case SM_CODE_SIGNING_INFORMATION:
default:
log_info("Unexpected PDU %u in SM_PH3_RECEIVE_KEYS", packet[0]);
break;default
}switch (sm_pdu_code) { ... }
if (sm_key_distribution_all_received()){
if (IS_RESPONDER(sm_conn->sm_role)){
sm_ctkd_start_from_br_edr(sm_conn);
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
sm_conn->sm_engine_state = SM_BR_EDR_DISTRIBUTE_KEYS;
}else { ... }
}if (sm_key_distribution_all_received()) { ... }
break;/* ... */
#endif
default:
log_info("Unexpected PDU %u in state %u", packet[0], sm_conn->sm_engine_state);
sm_pdu_received_in_wrong_state(sm_conn);
break;default
}switch (sm_conn->sm_engine_state) { ... }
sm_trigger_run();
}{ ... }
static void sm_channel_handler(uint8_t packet_type, hci_con_handle_t con_handle, uint8_t *packet, uint16_t size){
if ((packet_type == HCI_EVENT_PACKET) && (packet[0] == L2CAP_EVENT_CAN_SEND_NOW)){
sm_run();
}if ((packet_type == HCI_EVENT_PACKET) && (packet[0] == L2CAP_EVENT_CAN_SEND_NOW)) { ... }
uint8_t sm_pdu_code = sm_pdu_validate_and_get_opcode(packet_type, packet, size);
if (sm_pdu_code == 0) return;
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
if (sm_pdu_code == SM_CODE_PAIRING_FAILED){
sm_reencryption_complete(sm_conn, ERROR_CODE_AUTHENTICATION_FAILURE);
sm_pairing_complete(sm_conn, ERROR_CODE_AUTHENTICATION_FAILURE, packet[1]);
sm_done_for_handle(con_handle);
sm_conn->sm_engine_state = sm_conn->sm_role ? SM_RESPONDER_IDLE : SM_INITIATOR_CONNECTED;
return;
}if (sm_pdu_code == SM_CODE_PAIRING_FAILED) { ... }
if (sm_pdu_code == SM_CODE_KEYPRESS_NOTIFICATION){
uint8_t buffer[5];
buffer[0] = SM_EVENT_KEYPRESS_NOTIFICATION;
buffer[1] = 3;
little_endian_store_16(buffer, 2, con_handle);
buffer[4] = packet[1];
sm_dispatch_event(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
return;
}if (sm_pdu_code == SM_CODE_KEYPRESS_NOTIFICATION) { ... }
sm_pdu_handler(sm_conn, sm_pdu_code, packet);
}{ ... }
void sm_register_oob_data_callback( int (*get_oob_data_callback)(uint8_t address_type, bd_addr_t addr, uint8_t * oob_data)){
sm_get_oob_data = get_oob_data_callback;
}{ ... }
void sm_register_sc_oob_data_callback( int (*get_sc_oob_data_callback)(uint8_t address_type, bd_addr_t addr, uint8_t * oob_sc_peer_confirm, uint8_t * oob_sc_peer_random)){
sm_get_sc_oob_data = get_sc_oob_data_callback;
}{ ... }
void sm_register_ltk_callback( bool (*get_ltk_callback)(hci_con_handle_t con_handle, uint8_t address_type, bd_addr_t addr, uint8_t * ltk)){
sm_get_ltk_callback = get_ltk_callback;
}{ ... }
void sm_add_event_handler(btstack_packet_callback_registration_t * callback_handler){
btstack_linked_list_add_tail(&sm_event_handlers, (btstack_linked_item_t*) callback_handler);
}{ ... }
void sm_remove_event_handler(btstack_packet_callback_registration_t * callback_handler){
btstack_linked_list_remove(&sm_event_handlers, (btstack_linked_item_t*) callback_handler);
}{ ... }
void sm_set_accepted_stk_generation_methods(uint8_t accepted_stk_generation_methods){
sm_accepted_stk_generation_methods = accepted_stk_generation_methods;
}{ ... }
void sm_set_encryption_key_size_range(uint8_t min_size, uint8_t max_size){
sm_min_encryption_key_size = min_size;
sm_max_encryption_key_size = max_size;
}{ ... }
void sm_set_authentication_requirements(uint8_t auth_req){
#ifndef ENABLE_LE_SECURE_CONNECTIONS
if (auth_req & SM_AUTHREQ_SECURE_CONNECTION){
log_error("ENABLE_LE_SECURE_CONNECTIONS not defined, but requested by app. Dropping SC flag");
auth_req &= ~SM_AUTHREQ_SECURE_CONNECTION;
}if (auth_req & SM_AUTHREQ_SECURE_CONNECTION) { ... }
/* ... */#endif
sm_auth_req = auth_req;
}{ ... }
void sm_set_io_capabilities(io_capability_t io_capability){
sm_io_capabilities = io_capability;
}{ ... }
#ifdef ENABLE_LE_PERIPHERAL
void sm_set_request_security(bool enable){
sm_slave_request_security = enable;
}{ ... }
/* ... */#endif
void sm_set_er(sm_key_t er){
(void)memcpy(sm_persistent_er, er, 16);
}{ ... }
void sm_set_ir(sm_key_t ir){
(void)memcpy(sm_persistent_ir, ir, 16);
}{ ... }
void sm_test_set_irk(sm_key_t irk){
(void)memcpy(sm_persistent_irk, irk, 16);
dkg_state = DKG_CALC_DHK;
test_use_fixed_local_irk = true;
}{ ... }
void sm_test_use_fixed_local_csrk(void){
test_use_fixed_local_csrk = true;
}{ ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static void sm_ec_generated(void * arg){
UNUSED(arg);
ec_key_generation_state = EC_KEY_GENERATION_DONE;
sm_trigger_run();
}sm_ec_generated (void * arg) { ... }
static void sm_ec_generate_new_key(void) {
log_info("sm: generate new ec key");
#ifdef ENABLE_LE_SECURE_CONNECTIONS_DEBUG_KEY
const uint8_t debug_key_public[64] = {
0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c, 0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9,
0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb, 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6,
0xdc, 0x80, 0x9c, 0x49, 0x65, 0x2a, 0xeb, 0x6d, 0x63, 0x32, 0x9a, 0xbf, 0x5a, 0x52, 0x15, 0x5c,
0x76, 0x63, 0x45, 0xc2, 0x8f, 0xed, 0x30, 0x24, 0x74, 0x1c, 0x8e, 0xd0, 0x15, 0x89, 0xd2, 0x8b
...};
const uint8_t debug_key_private[32] = {
0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, 0x74, 0xc9, 0xb3, 0xe3, 0xd2, 0x10, 0x3f, 0x50,
0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99, 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd
...};
if (sm_sc_debug_keys_enabled) {
memcpy(ec_q, debug_key_public, 64);
btstack_crypto_ecc_p256_set_key(debug_key_public, debug_key_private);
ec_key_generation_state = EC_KEY_GENERATION_DONE;
}if (sm_sc_debug_keys_enabled) { ... } else
#endif
{
ec_key_generation_state = EC_KEY_GENERATION_ACTIVE;
btstack_crypto_ecc_p256_generate_key(&sm_crypto_ecc_p256_request, ec_q, &sm_ec_generated, NULL);
}else { ... }
}sm_ec_generate_new_key (void) { ... }
/* ... */#endif
#ifdef ENABLE_TESTING_SUPPORT
void sm_test_set_pairing_failure(int reason){
test_pairing_failure = reason;
}sm_test_set_pairing_failure (int reason) { ... }
/* ... */#endif
static void sm_state_reset(void) {
#ifdef USE_CMAC_ENGINE
sm_cmac_active = 0;
#endif
dkg_state = DKG_W4_WORKING;
rau_state = RAU_IDLE;
sm_aes128_state = SM_AES128_IDLE;
sm_address_resolution_test = -1;
sm_address_resolution_mode = ADDRESS_RESOLUTION_IDLE;
sm_address_resolution_general_queue = NULL;
sm_active_connection_handle = HCI_CON_HANDLE_INVALID;
sm_persistent_keys_random_active = false;
#ifdef ENABLE_LE_SECURE_CONNECTIONS
ec_key_generation_state = EC_KEY_GENERATION_IDLE;
#endif
}{ ... }
void sm_init(void){
if (sm_initialized) return;
sm_er_ir_set_default();
sm_accepted_stk_generation_methods = SM_STK_GENERATION_METHOD_JUST_WORKS
| SM_STK_GENERATION_METHOD_OOB
| SM_STK_GENERATION_METHOD_PASSKEY
| SM_STK_GENERATION_METHOD_NUMERIC_COMPARISON;
sm_max_encryption_key_size = 16;
sm_min_encryption_key_size = 7;
sm_fixed_passkey_in_display_role = 0xffffffffU;
sm_reconstruct_ltk_without_le_device_db_entry = true;
gap_random_adress_update_period = 15 * 60 * 1000L;
test_use_fixed_local_csrk = false;
btstack_run_loop_set_timer_handler(&sm_run_timer, &sm_run_timer_handler);
hci_event_callback_registration.callback = &sm_event_packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
l2cap_event_callback_registration.callback = &sm_event_packet_handler;
l2cap_add_event_handler(&l2cap_event_callback_registration);/* ... */
#endif
btstack_crypto_init();
le_device_db_init();
l2cap_register_fixed_channel(sm_channel_handler, L2CAP_CID_SECURITY_MANAGER_PROTOCOL);
#ifdef ENABLE_CLASSIC
l2cap_register_fixed_channel(sm_channel_handler, L2CAP_CID_BR_EDR_SECURITY_MANAGER);
#endif
sm_state_reset();
sm_initialized = true;
}{ ... }
void sm_deinit(void){
sm_initialized = false;
btstack_run_loop_remove_timer(&sm_run_timer);
#if defined(ENABLE_LE_SECURE_CONNECTIONS) && defined (ENABLE_LE_SECURE_CONNECTION_DEBUG_KEY)
sm_sc_debug_keys_enabled = false;
#endif
}{ ... }
void sm_use_fixed_passkey_in_display_role(uint32_t passkey){
sm_fixed_passkey_in_display_role = passkey;
}{ ... }
void sm_allow_ltk_reconstruction_without_le_device_db_entry(int allow){
sm_reconstruct_ltk_without_le_device_db_entry = allow != 0;
}{ ... }
static sm_connection_t * sm_get_connection_for_handle(hci_con_handle_t con_handle){
hci_connection_t * hci_con = hci_connection_for_handle(con_handle);
if (!hci_con) return NULL;
return &hci_con->sm_connection;
}{ ... }
static void sm_cache_ltk(sm_connection_t * connection, const sm_key_t ltk){
hci_connection_t * hci_con = hci_connection_for_handle(connection->sm_handle);
btstack_assert(hci_con != NULL);
memcpy(hci_con->link_key, ltk, 16);
hci_con->link_key_type = COMBINATION_KEY;
}{ ... }
#ifdef ENABLE_CROSS_TRANSPORT_KEY_DERIVATION
static sm_connection_t * sm_get_connection_for_bd_addr_and_type(bd_addr_t address, bd_addr_type_t addr_type){
hci_connection_t * hci_con = hci_connection_for_bd_addr_and_type(address, addr_type);
if (!hci_con) return NULL;
return &hci_con->sm_connection;
}sm_get_connection_for_bd_addr_and_type (bd_addr_t address, bd_addr_type_t addr_type) { ... }
/* ... */#endif
void sm_send_security_request(hci_con_handle_t con_handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
if (!IS_RESPONDER(sm_conn->sm_role)) return;
sm_request_pairing(con_handle);
}{ ... }
void sm_request_pairing(hci_con_handle_t con_handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
bool have_ltk;
uint8_t ltk[16];
bool auth_required;
int authenticated;
bool trigger_reencryption;
log_info("sm_request_pairing in role %u, state %u", sm_conn->sm_role, sm_conn->sm_engine_state);
if (IS_RESPONDER(sm_conn->sm_role)){
switch (sm_conn->sm_engine_state){
case SM_GENERAL_IDLE:
case SM_RESPONDER_IDLE:
switch (sm_conn->sm_irk_lookup_state){
case IRK_LOOKUP_SUCCEEDED:
le_device_db_encryption_get(sm_conn->sm_le_db_index, NULL, NULL, ltk, NULL, NULL, NULL, NULL);
have_ltk = !sm_is_null_key(ltk);
log_info("have ltk %u", have_ltk);
if (have_ltk){
sm_conn->sm_pairing_requested = true;
sm_conn->sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST;
sm_reencryption_started(sm_conn);
break;
}if (have_ltk) { ... }
case IRK_LOOKUP_SUCCEEDED:
case IRK_LOOKUP_FAILED:
sm_conn->sm_pairing_requested = true;
sm_conn->sm_engine_state = SM_RESPONDER_SEND_SECURITY_REQUEST;
sm_pairing_started(sm_conn);
break;case IRK_LOOKUP_FAILED:
default:
log_info("irk lookup pending");
sm_conn->sm_pairing_requested = true;
break;default
}switch (sm_conn->sm_irk_lookup_state) { ... }
break;case SM_RESPONDER_IDLE:
default:
break;default
}switch (sm_conn->sm_engine_state) { ... }
}if (IS_RESPONDER(sm_conn->sm_role)) { ... } else {
switch (sm_conn->sm_engine_state){
case SM_INITIATOR_CONNECTED:
switch (sm_conn->sm_irk_lookup_state){
case IRK_LOOKUP_SUCCEEDED:
le_device_db_encryption_get(sm_conn->sm_le_db_index, NULL, NULL, ltk, NULL, &authenticated, NULL, NULL);
have_ltk = !sm_is_null_key(ltk);
auth_required = sm_auth_req & SM_AUTHREQ_MITM_PROTECTION;
trigger_reencryption = have_ltk && ((authenticated != 0) || (auth_required == false));
log_info("have ltk %u, authenticated %u, auth required %u => reencrypt %u", have_ltk, authenticated, auth_required, trigger_reencryption);
if (trigger_reencryption){
sm_conn->sm_pairing_requested = true;
sm_conn->sm_engine_state = SM_INITIATOR_PH4_HAS_LTK;
break;
}if (trigger_reencryption) { ... }
case IRK_LOOKUP_SUCCEEDED:
case IRK_LOOKUP_FAILED:
sm_conn->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
break;case IRK_LOOKUP_FAILED:
default:
log_info("irk lookup pending");
sm_conn->sm_pairing_requested = true;
break;default
}switch (sm_conn->sm_irk_lookup_state) { ... }
break;case SM_INITIATOR_CONNECTED:
case SM_GENERAL_REENCRYPTION_FAILED:
sm_conn->sm_engine_state = SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST;
break;case SM_GENERAL_REENCRYPTION_FAILED:
case SM_GENERAL_IDLE:
sm_conn->sm_pairing_requested = true;
break;case SM_GENERAL_IDLE:
default:
break;default
}switch (sm_conn->sm_engine_state) { ... }
}else { ... }
sm_trigger_run();
}{ ... }
void sm_authorization_decline(hci_con_handle_t con_handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
sm_conn->sm_connection_authorization_state = AUTHORIZATION_DECLINED;
sm_notify_client_status(SM_EVENT_AUTHORIZATION_RESULT, sm_conn->sm_handle, sm_conn->sm_peer_addr_type, sm_conn->sm_peer_address, 0);
}{ ... }
void sm_authorization_grant(hci_con_handle_t con_handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
sm_conn->sm_connection_authorization_state = AUTHORIZATION_GRANTED;
sm_notify_client_status(SM_EVENT_AUTHORIZATION_RESULT, sm_conn->sm_handle, sm_conn->sm_peer_addr_type, sm_conn->sm_peer_address, 1);
}{ ... }
void sm_bonding_decline(hci_con_handle_t con_handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
setup->sm_user_response = SM_USER_RESPONSE_DECLINE;
log_info("decline, state %u", sm_conn->sm_engine_state);
switch(sm_conn->sm_engine_state){
#ifdef ENABLE_LE_SECURE_CONNECTIONS
case SM_SC_W4_USER_RESPONSE:
case SM_SC_W4_CONFIRMATION:
case SM_SC_W4_PUBLIC_KEY_COMMAND:/* ... */
#endif
case SM_PH1_W4_USER_RESPONSE:
switch (setup->sm_stk_generation_method){
case PK_RESP_INPUT:
case PK_INIT_INPUT:
case PK_BOTH_INPUT:
sm_pairing_error(sm_conn, SM_REASON_PASSKEY_ENTRY_FAILED);
break;case PK_BOTH_INPUT:
case NUMERIC_COMPARISON:
sm_pairing_error(sm_conn, SM_REASON_NUMERIC_COMPARISON_FAILED);
break;case NUMERIC_COMPARISON:
case JUST_WORKS:
case OOB:
sm_pairing_error(sm_conn, SM_REASON_UNSPECIFIED_REASON);
break;case OOB:
default:
btstack_assert(false);
break;default
}switch (setup->sm_stk_generation_method) { ... }
break;case SM_PH1_W4_USER_RESPONSE:
default:
break;default
}switch (sm_conn->sm_engine_state) { ... }
sm_trigger_run();
}{ ... }
void sm_just_works_confirm(hci_con_handle_t con_handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
setup->sm_user_response = SM_USER_RESPONSE_CONFIRM;
if (sm_conn->sm_engine_state == SM_PH1_W4_USER_RESPONSE){
if (setup->sm_use_secure_connections){
sm_conn->sm_engine_state = SM_SC_SEND_PUBLIC_KEY_COMMAND;
}if (setup->sm_use_secure_connections) { ... } else {
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_random, 16, &sm_handle_random_result_ph2_random, (void *)(uintptr_t) sm_conn->sm_handle);
}else { ... }
}if (sm_conn->sm_engine_state == SM_PH1_W4_USER_RESPONSE) { ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
if (sm_conn->sm_engine_state == SM_SC_W4_USER_RESPONSE){
sm_sc_prepare_dhkey_check(sm_conn);
}if (sm_conn->sm_engine_state == SM_SC_W4_USER_RESPONSE) { ... }
/* ... */#endif
sm_trigger_run();
}{ ... }
void sm_numeric_comparison_confirm(hci_con_handle_t con_handle){
sm_just_works_confirm(con_handle);
}{ ... }
void sm_passkey_input(hci_con_handle_t con_handle, uint32_t passkey){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
sm_reset_tk();
big_endian_store_32(setup->sm_tk, 12, passkey);
setup->sm_user_response = SM_USER_RESPONSE_PASSKEY;
if (sm_conn->sm_engine_state == SM_PH1_W4_USER_RESPONSE){
btstack_crypto_random_generate(&sm_crypto_random_request, setup->sm_local_random, 16, &sm_handle_random_result_ph2_random, (void *)(uintptr_t) sm_conn->sm_handle);
}if (sm_conn->sm_engine_state == SM_PH1_W4_USER_RESPONSE) { ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
(void)memcpy(setup->sm_ra, setup->sm_tk, 16);
(void)memcpy(setup->sm_rb, setup->sm_tk, 16);
if (sm_conn->sm_engine_state == SM_SC_W4_USER_RESPONSE){
sm_sc_start_calculating_local_confirm(sm_conn);
}if (sm_conn->sm_engine_state == SM_SC_W4_USER_RESPONSE) { ... }
/* ... */#endif
sm_trigger_run();
}{ ... }
void sm_keypress_notification(hci_con_handle_t con_handle, uint8_t action){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return;
if (action > SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED) return;
uint8_t num_actions = setup->sm_keypress_notification >> 5;
uint8_t flags = setup->sm_keypress_notification & 0x1fu;
switch (action){
case SM_KEYPRESS_PASSKEY_ENTRY_STARTED:
case SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED:
flags |= (1u << action);
break;case SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED:
case SM_KEYPRESS_PASSKEY_CLEARED:
flags = (flags & 0x19u) | (1u << SM_KEYPRESS_PASSKEY_CLEARED);
break;case SM_KEYPRESS_PASSKEY_CLEARED:
case SM_KEYPRESS_PASSKEY_DIGIT_ENTERED:
if ((flags & (1u << SM_KEYPRESS_PASSKEY_DIGIT_ERASED)) != 0u){
num_actions--;
if (num_actions == 0u){
flags &= 0x19u;
}if (num_actions == 0u) { ... }
break;
}if ((flags & (1u << SM_KEYPRESS_PASSKEY_DIGIT_ERASED)) != 0u) { ... }
num_actions++;
flags |= (1u << SM_KEYPRESS_PASSKEY_DIGIT_ENTERED);
break;case SM_KEYPRESS_PASSKEY_DIGIT_ENTERED:
case SM_KEYPRESS_PASSKEY_DIGIT_ERASED:
if ((flags & (1u << SM_KEYPRESS_PASSKEY_DIGIT_ENTERED)) != 0u){
num_actions--;
if (num_actions == 0u){
flags &= 0x19u;
}if (num_actions == 0u) { ... }
break;
}if ((flags & (1u << SM_KEYPRESS_PASSKEY_DIGIT_ENTERED)) != 0u) { ... }
num_actions++;
flags |= (1u << SM_KEYPRESS_PASSKEY_DIGIT_ERASED);
break;case SM_KEYPRESS_PASSKEY_DIGIT_ERASED:
default:
break;default
}switch (action) { ... }
setup->sm_keypress_notification = (num_actions << 5) | flags;
sm_trigger_run();
}{ ... }
#ifdef ENABLE_LE_SECURE_CONNECTIONS
static void sm_handle_random_result_oob(void * arg){
UNUSED(arg);
sm_sc_oob_state = SM_SC_OOB_W2_CALC_CONFIRM;
sm_trigger_run();
}sm_handle_random_result_oob (void * arg) { ... }
uint8_t sm_generate_sc_oob_data(void (*callback)(const uint8_t * confirm_value, const uint8_t * random_value)){
static btstack_crypto_random_t sm_crypto_random_oob_request;
if (sm_sc_oob_state != SM_SC_OOB_IDLE) return ERROR_CODE_COMMAND_DISALLOWED;
sm_sc_oob_callback = callback;
sm_sc_oob_state = SM_SC_OOB_W4_RANDOM;
btstack_crypto_random_generate(&sm_crypto_random_oob_request, sm_sc_oob_random, 16, &sm_handle_random_result_oob, NULL);
return 0;
}sm_generate_sc_oob_data (void (*callback)(const uint8_t * confirm_value, const uint8_t * random_value)) { ... }
/* ... */#endif
/* ... */
irk_lookup_state_t sm_identity_resolving_state(hci_con_handle_t con_handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return IRK_LOOKUP_IDLE;
return sm_conn->sm_irk_lookup_state;
}{ ... }
/* ... */
int sm_le_device_index(hci_con_handle_t con_handle ){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return -1;
return sm_conn->sm_le_db_index;
}{ ... }
uint8_t sm_get_ltk(hci_con_handle_t con_handle, sm_key_t ltk){
hci_connection_t * hci_connection = hci_connection_for_handle(con_handle);
if (hci_connection == NULL){
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}if (hci_connection == NULL) { ... }
if (hci_connection->link_key_type == INVALID_LINK_KEY){
return ERROR_CODE_PIN_OR_KEY_MISSING;
}if (hci_connection->link_key_type == INVALID_LINK_KEY) { ... }
memcpy(ltk, hci_connection->link_key, 16);
return ERROR_CODE_SUCCESS;
}{ ... }
static int gap_random_address_type_requires_updates(void){
switch (gap_random_adress_type){
case GAP_RANDOM_ADDRESS_TYPE_OFF:
case GAP_RANDOM_ADDRESS_TYPE_STATIC:
return 0;case GAP_RANDOM_ADDRESS_TYPE_STATIC:
default:
return 1;default
}switch (gap_random_adress_type) { ... }
}{ ... }
static uint8_t own_address_type(void){
switch (gap_random_adress_type){
case GAP_RANDOM_ADDRESS_TYPE_OFF:
return BD_ADDR_TYPE_LE_PUBLIC;case GAP_RANDOM_ADDRESS_TYPE_OFF:
default:
return BD_ADDR_TYPE_LE_RANDOM;default
}switch (gap_random_adress_type) { ... }
}{ ... }
void gap_random_address_set_mode(gap_random_address_type_t random_address_type){
gap_random_address_update_stop();
gap_random_adress_type = random_address_type;
hci_le_set_own_address_type(own_address_type());
if (!gap_random_address_type_requires_updates()) return;
gap_random_address_update_start();
gap_random_address_trigger();
}{ ... }
gap_random_address_type_t gap_random_address_get_mode(void){
return gap_random_adress_type;
}{ ... }
void gap_random_address_set_update_period(int period_ms){
gap_random_adress_update_period = period_ms;
if (!gap_random_address_type_requires_updates()) return;
gap_random_address_update_stop();
gap_random_address_update_start();
}{ ... }
void gap_random_address_set(const bd_addr_t addr){
gap_random_address_set_mode(GAP_RANDOM_ADDRESS_TYPE_STATIC);
(void)memcpy(sm_random_address, addr, 6);
sm_random_address[0] |= 0xc0;
hci_le_random_address_set(sm_random_address);
}{ ... }
#ifdef ENABLE_LE_PERIPHERAL
/* ... */
void gap_advertisements_set_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type,
uint8_t direct_address_typ, bd_addr_t direct_address, uint8_t channel_map, uint8_t filter_policy){
hci_le_advertisements_set_params(adv_int_min, adv_int_max, adv_type,
direct_address_typ, direct_address, channel_map, filter_policy);
}{ ... }
#endif/* ... */
bool gap_reconnect_security_setup_active(hci_con_handle_t con_handle){
sm_connection_t * sm_conn = sm_get_connection_for_handle(con_handle);
if (!sm_conn) return false;
if (sm_conn->sm_connection_encrypted) return false;
switch(sm_conn->sm_irk_lookup_state){
case IRK_LOOKUP_FAILED:
return false;case IRK_LOOKUP_FAILED:
case IRK_LOOKUP_SUCCEEDED:
break;case IRK_LOOKUP_SUCCEEDED:
default:
return true;default
}switch (sm_conn->sm_irk_lookup_state) { ... }
if (sm_conn->sm_engine_state == SM_GENERAL_REENCRYPTION_FAILED) return false;
if (sm_conn->sm_role != 0){
return sm_conn->sm_engine_state != SM_RESPONDER_IDLE;
}if (sm_conn->sm_role != 0) { ... } else {
return sm_conn->sm_engine_state != SM_INITIATOR_CONNECTED;
}else { ... }
}{ ... }
void sm_set_secure_connections_only_mode(bool enable){
#ifdef ENABLE_LE_SECURE_CONNECTIONS
sm_sc_only_mode = enable;
#else
btstack_assert(enable == false);/* ... */
#endif
}{ ... }
#if defined(ENABLE_LE_SECURE_CONNECTIONS) && defined (ENABLE_LE_SECURE_CONNECTION_DEBUG_KEY)
void sm_test_enable_secure_connections_debug_keys(void) {
log_info("Enable LE Secure Connection Debug Keys for testing");
sm_sc_debug_keys_enabled = true;
sm_ec_generate_new_key();
}sm_test_enable_secure_connections_debug_keys (void) { ... }
/* ... */#endif
const uint8_t * gap_get_persistent_irk(void){
return sm_persistent_irk;
}{ ... }
void gap_delete_bonding(bd_addr_type_t address_type, bd_addr_t address){
int index = sm_le_device_db_index_lookup(address_type, address);
if (index >= 0){
sm_remove_le_device_db_entry(index);
}if (index >= 0) { ... }
}{ ... }