1 /******************************************************************************
2  *
3  *  Copyright 2021-2024 NXP
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 #define LOG_TAG "SBAccessController"
19 
20 #include <android-base/logging.h>
21 #include <map>
22 #include <vector>
23 
24 #include <EseTransportUtils.h>
25 #include <SBAccessController.h>
26 
27 #define UPGRADE_OFFSET_SW 3    // upgrade offset from last in response
28 #define UPGRADE_MASK_BIT 0x02  // Update bit mask in upgrade byte
29 #define UPGRADE_MASK_VAL 0x02  // Update mask value in upgrade byte
30 
31 namespace keymint::javacard {
32 
33 static bool g_AccessAllowed = true;
34 static std::atomic<uint8_t> g_NumOfCryptoOps = 0;
35 
36 // These should be in sync with JavacardKeymasterDevice41.cpp
37 // Allow listed cmds
38 std::map<uint8_t, uint8_t> allowedCmdIns = {{0x2D /*INS_GET_HMAC_SHARING_PARAM*/, 0},
39                                             {0x2A /*INS_COMPUTE_SHARED_HMAC*/, 0},
40                                             {0x4D /*INS_GET_ROT_CHALLENGE_CMD*/, 0}};
41 
CryptoOpTimerFunc(union sigval arg)42 static void CryptoOpTimerFunc(union sigval arg) {
43     (void)arg;  // unused
44     LOG(DEBUG) << "CryptoOperation timer expired";
45     g_NumOfCryptoOps = 0;
46 }
47 
AccessTimerFunc(union sigval arg)48 static void AccessTimerFunc(union sigval arg) {
49     (void)arg;  // unused
50     LOG(DEBUG) << "Applet access-block timer expired";
51     g_AccessAllowed = true;
52 }
getInstance()53 SBAccessController& SBAccessController::getInstance() {
54     static SBAccessController sb_access_cntrl;
55     return sb_access_cntrl;
56 }
startTimer(bool isStart,IntervalTimer & t,int timeout,void (* timerFunc)(union sigval))57 void SBAccessController::startTimer(bool isStart, IntervalTimer& t, int timeout,
58                                     void (*timerFunc)(union sigval)) {
59     t.kill();
60     if (isStart) {
61         t.set(timeout, this, timerFunc);
62     }
63 }
64 
parseResponse(std::vector<uint8_t> & responseApdu)65 void SBAccessController::parseResponse(std::vector<uint8_t>& responseApdu) {
66     // check if StrongBox Applet update is underway
67     if ((responseApdu[responseApdu.size() - UPGRADE_OFFSET_SW] & UPGRADE_MASK_BIT) ==
68         UPGRADE_MASK_VAL) {
69         mIsUpdateInProgress = true;
70         LOG(INFO) << "StrongBox Applet update is in progress";
71         g_AccessAllowed = false;  // No access or Limited access
72         startTimer(true, mTimer, SB_ACCESS_BLOCK_TIMER, AccessTimerFunc);
73     } else {
74         mIsUpdateInProgress = false;
75         g_AccessAllowed = true;  // Full access
76         startTimer(false, mTimer, 0, nullptr);
77     }
78 }
getSessionTimeout()79 int SBAccessController::getSessionTimeout() {
80     if (mIsUpdateInProgress) {
81         return (mBootState == BOOTSTATE::SB_EARLY_BOOT_ENDED) ? SMALLEST_SESSION_TIMEOUT
82                                                               : UPGRADE_SESSION_TIMEOUT;
83     } else {
84         return (g_NumOfCryptoOps > 0) ? CRYPTO_OP_SESSION_TIMEOUT : REGULAR_SESSION_TIMEOUT;
85     }
86 }
isSelectAllowed()87 bool SBAccessController::isSelectAllowed() {
88     bool select_allowed = false;
89     if (g_AccessAllowed) {
90         select_allowed = true;
91     } else {
92         switch (mBootState) {
93             case BOOTSTATE::SB_EARLY_BOOT:
94                 select_allowed = true;
95                 break;
96             case BOOTSTATE::SB_EARLY_BOOT_ENDED:
97                 break;
98         }
99     }
100     if(!select_allowed)
101         LOG(INFO) << "StrongBox Applet selection is not allowed";
102 
103     return select_allowed;
104 }
updateBootState()105 void SBAccessController::updateBootState() {
106     // set the state to BOOT_ENDED once we have received
107     // all allowed commands
108     bool allCmdreceived = true;
109     for (auto it = allowedCmdIns.begin(); it != allowedCmdIns.end(); it++) {
110         if (it->second == 0) {
111             allCmdreceived = false;
112             break;
113         }
114     }
115     if (allCmdreceived) {
116         LOG(INFO) << "All allowlisted cmds received , mark Early boot completed";
117         mBootState = BOOTSTATE::SB_EARLY_BOOT_ENDED;
118     }
119 }
setCryptoOperationState(uint8_t opState)120 void SBAccessController::setCryptoOperationState(uint8_t opState) {
121     if (opState == OPERATION_STATE::OP_STARTED) {
122         g_NumOfCryptoOps++;
123         startTimer(true, mTimerCrypto, CRYPTO_OP_SESSION_TIMEOUT, CryptoOpTimerFunc);
124     } else if (opState == OPERATION_STATE::OP_FINISHED) {
125         if (g_NumOfCryptoOps > 0) g_NumOfCryptoOps--;
126         if (g_NumOfCryptoOps == 0) {
127             LOG(INFO) << "All crypto operations finished";
128             startTimer(false, mTimerCrypto, 0, nullptr);
129         }
130     }
131     LOG(INFO) << "Number of operations running: " << std::to_string(g_NumOfCryptoOps);
132 }
isOperationAllowed(uint8_t cmdIns)133 bool SBAccessController::isOperationAllowed(uint8_t cmdIns) {
134     bool op_allowed = false;
135     if (g_AccessAllowed) {
136         op_allowed = true;
137     } else {
138         switch (mBootState) {
139             case BOOTSTATE::SB_EARLY_BOOT: {
140                 auto it = allowedCmdIns.find(cmdIns);
141                 if (it != allowedCmdIns.end()) {
142                     it->second = 1;  // cmd received
143                     updateBootState();
144                     op_allowed = true;
145                 }
146             } break;
147             case BOOTSTATE::SB_EARLY_BOOT_ENDED:
148                 break;
149         }
150     }
151     if (cmdIns == EARLY_BOOT_ENDED_CMD || cmdIns == INS_SEND_ROT_DATA_CMD) {
152         // allowed as these may be received during early boot
153         op_allowed = true;
154     }
155     return op_allowed;
156 }
157 }  // namespace keymint::javacard
158