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