ble_sm: add Secure Connections Only mode

Added mode allowing to enforce pairing only in SC mode 1 level 4. This mode is required to pass
GAP/SEC/SEM/BI testcases. Added BLE_SM_SC_LVL config to allow pairing only in selected levels.
diff --git a/nimble/host/src/ble_att_svr.c b/nimble/host/src/ble_att_svr.c
index 0cfbc7d..7b2611a 100644
--- a/nimble/host/src/ble_att_svr.c
+++ b/nimble/host/src/ble_att_svr.c
@@ -284,6 +284,16 @@
     }
 
     ble_att_svr_get_sec_state(conn_handle, &sec_state);
+    /* In SC Only mode all characteristics requiring security
+     * require it on level 4
+     */
+    if (MYNEWT_VAL(BLE_SM_SC_ONLY)) {
+        if (sec_state.key_size != 128 ||
+            !sec_state.authenticated ||
+            !sec_state.encrypted) {
+            return BLE_ATT_ERR_INSUFFICIENT_KEY_SZ;
+        }
+    }
     if ((enc || authen) && !sec_state.encrypted) {
         ble_hs_lock();
         conn = ble_hs_conn_find(conn_handle);
diff --git a/nimble/host/src/ble_sm.c b/nimble/host/src/ble_sm.c
index b4e8096..c63af40 100644
--- a/nimble/host/src/ble_sm.c
+++ b/nimble/host/src/ble_sm.c
@@ -1726,17 +1726,23 @@
 }
 
 static bool
-ble_sm_verify_auth_requirements(uint8_t authreq)
+ble_sm_verify_auth_requirements(uint8_t cmd)
 {
     /* For now we check only SC only mode. I.e.: when remote indicates
      * to not support SC pairing, let us make sure legacy pairing is supported
      * on our side. If not, we can fail right away.
      */
-    if (!(authreq & BLE_SM_PAIR_AUTHREQ_SC)) {
+    if (!(cmd & BLE_SM_PAIR_AUTHREQ_SC)) {
         if (MYNEWT_VAL(BLE_SM_LEGACY) == 0) {
             return false;
         }
     }
+    /* Fail if Secure Connections level forces MITM protection and remote does not
+     * support it
+     */
+    if (MYNEWT_VAL(BLE_SM_SC_LVL) >= 3 && !(cmd & BLE_SM_PAIR_AUTHREQ_MITM)) {
+        return false;
+    }
     return true;
 }
 
@@ -1817,12 +1823,21 @@
         if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) {
             res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
+        } else if (MYNEWT_VAL(BLE_SM_SC_LVL) == 1) {
+            res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
+            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
         } else if (req->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) {
             res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
         } else if (req->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) {
             res->sm_err = BLE_SM_ERR_INVAL;
             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
+        } else if (MYNEWT_VAL(BLE_SM_SC_ONLY) && (req->max_enc_key_size != BLE_SM_PAIR_KEY_SZ_MAX)) {
+            /* Fail if Secure Connections Only mode is on and remote does not meet
+            * key size requirements - MITM was checked in last step
+            */
+            res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
+            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
         } else if (!ble_sm_verify_auth_requirements(req->authreq)) {
             res->sm_err = BLE_SM_ERR_AUTHREQ;
             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
@@ -1886,6 +1901,12 @@
         } else if (rsp->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) {
             res->sm_err = BLE_SM_ERR_INVAL;
             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
+        } else if (MYNEWT_VAL(BLE_SM_SC_ONLY) && (rsp->max_enc_key_size != BLE_SM_PAIR_KEY_SZ_MAX)) {
+            /* Fail if Secure Connections Only mode is on and remote does not meet
+            * key size requirements - MITM was checked in last step
+            */
+            res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
+            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
         } else if (!ble_sm_verify_auth_requirements(rsp->authreq)) {
             res->sm_err = BLE_SM_ERR_AUTHREQ;
             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
diff --git a/nimble/host/syscfg.yml b/nimble/host/syscfg.yml
index e72e8d5..c814ba5 100644
--- a/nimble/host/syscfg.yml
+++ b/nimble/host/syscfg.yml
@@ -133,6 +133,34 @@
         description: 'Security manager secure connections (4.2).'
         value: 0
 
+    BLE_SM_SC_ONLY:
+        description: >
+            Force global Secure Connections Pairing Only mode. This means
+            that only SC pairing mode 1 level 4 shall be used, and all
+            characteristics will require it to access, except these
+            requiring mode 1 level 1.
+        value: 0
+        restrictions:
+            - 'BLE_SM_SC_LVL == 4 if 1'
+
+    BLE_SM_SC_LVL:
+        description: >
+          Force global Secure Connections mode 1 level. This level
+          describes requirements for pairing response/request received
+          to accept pairing:
+          - 1 - do not pair; only access to characteristics with no
+                authentication requirements is granted
+          - 2 - allow to pair despite MITM being on or off
+          - 3 - allow to pair only when MITM protection is on
+          - 4 - allow to pair only when 128 bit key is used and MITM is on
+          When set to 0 level is no forced and pairing is allowed for all
+          requests/responses with valid values (for example pairing will be
+          rejected with key longer than 128 bits). Successful pairing with
+          insufficient security will still cause denying access to protected
+          GATT characteristics.
+        value: 0
+        range: 0..4
+
     BLE_SM_MAX_PROCS:
         description: >
             The maximum number of concurrent security manager procedures.
diff --git a/porting/examples/linux/include/syscfg/syscfg.h b/porting/examples/linux/include/syscfg/syscfg.h
index 99939f2..8363336 100644
--- a/porting/examples/linux/include/syscfg/syscfg.h
+++ b/porting/examples/linux/include/syscfg/syscfg.h
@@ -735,6 +735,14 @@
 #define MYNEWT_VAL_BLE_SM_SC (0)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY
+#define MYNEWT_VAL_BLE_SM_SC_ONLY (0)
+#endif
+
+#ifndef MYNEWT_VAL_BLE_SM_SC_LVL
+#define MYNEWT_VAL_BLE_SM_SC_LVL (0)
+#endif
+
 #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS
 #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0)
 #endif
diff --git a/porting/examples/linux_blemesh/include/syscfg/syscfg.h b/porting/examples/linux_blemesh/include/syscfg/syscfg.h
index 9aac106..a3df8b6 100644
--- a/porting/examples/linux_blemesh/include/syscfg/syscfg.h
+++ b/porting/examples/linux_blemesh/include/syscfg/syscfg.h
@@ -738,6 +738,14 @@
 #define MYNEWT_VAL_BLE_SM_SC (1)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY
+#define MYNEWT_VAL_BLE_SM_SC_ONLY (0)
+#endif
+
+#ifndef MYNEWT_VAL_BLE_SM_SC_LVL
+#define MYNEWT_VAL_BLE_SM_SC_LVL (0)
+#endif
+
 #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS
 #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0)
 #endif
diff --git a/porting/examples/nuttx/include/syscfg/syscfg.h b/porting/examples/nuttx/include/syscfg/syscfg.h
index ff73312..c8ad4e4 100644
--- a/porting/examples/nuttx/include/syscfg/syscfg.h
+++ b/porting/examples/nuttx/include/syscfg/syscfg.h
@@ -785,6 +785,14 @@
 #define MYNEWT_VAL_BLE_SM_SC (1)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY
+#define MYNEWT_VAL_BLE_SM_SC_ONLY (0)
+#endif
+
+#ifndef MYNEWT_VAL_BLE_SM_SC_LVL
+#define MYNEWT_VAL_BLE_SM_SC_LVL (0)
+#endif
+
 #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS
 #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0)
 #endif
diff --git a/porting/nimble/include/syscfg/syscfg.h b/porting/nimble/include/syscfg/syscfg.h
index c4b70db..cfc10ed 100644
--- a/porting/nimble/include/syscfg/syscfg.h
+++ b/porting/nimble/include/syscfg/syscfg.h
@@ -734,6 +734,14 @@
 #define MYNEWT_VAL_BLE_SM_SC (0)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY
+#define MYNEWT_VAL_BLE_SM_SC_ONLY (0)
+#endif
+
+#ifndef MYNEWT_VAL_BLE_SM_SC_LVL
+#define MYNEWT_VAL_BLE_SM_SC_LVL (0)
+#endif
+
 #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS
 #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0)
 #endif
diff --git a/porting/npl/riot/include/syscfg/syscfg.h b/porting/npl/riot/include/syscfg/syscfg.h
index f7406f0..e3d282e 100644
--- a/porting/npl/riot/include/syscfg/syscfg.h
+++ b/porting/npl/riot/include/syscfg/syscfg.h
@@ -1487,6 +1487,14 @@
 #define MYNEWT_VAL_BLE_SM_SC (0)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY
+#define MYNEWT_VAL_BLE_SM_SC_ONLY (0)
+#endif
+
+#ifndef MYNEWT_VAL_BLE_SM_SC_LVL
+#define MYNEWT_VAL_BLE_SM_SC_LVL (0)
+#endif
+
 #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS
 #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0)
 #endif