xref: /aosp_15_r20/external/libese/esed/utils.h (revision 5c4dab75aa57366379dce576b1a9e082a44e2b3a)
1*5c4dab75SAndroid Build Coastguard Worker /*
2*5c4dab75SAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*5c4dab75SAndroid Build Coastguard Worker  *
4*5c4dab75SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*5c4dab75SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*5c4dab75SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*5c4dab75SAndroid Build Coastguard Worker  *
8*5c4dab75SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*5c4dab75SAndroid Build Coastguard Worker  *
10*5c4dab75SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*5c4dab75SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*5c4dab75SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5c4dab75SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*5c4dab75SAndroid Build Coastguard Worker  * limitations under the License.
15*5c4dab75SAndroid Build Coastguard Worker  */
16*5c4dab75SAndroid Build Coastguard Worker 
17*5c4dab75SAndroid Build Coastguard Worker #ifndef ESED_PN81A_UTILS_H_
18*5c4dab75SAndroid Build Coastguard Worker #define ESED_PN81A_UTILS_H_
19*5c4dab75SAndroid Build Coastguard Worker 
20*5c4dab75SAndroid Build Coastguard Worker #include <functional>
21*5c4dab75SAndroid Build Coastguard Worker #include <string>
22*5c4dab75SAndroid Build Coastguard Worker 
23*5c4dab75SAndroid Build Coastguard Worker #include <hidl/Status.h>
24*5c4dab75SAndroid Build Coastguard Worker 
25*5c4dab75SAndroid Build Coastguard Worker #include <apdu/apdu.h>
26*5c4dab75SAndroid Build Coastguard Worker 
27*5c4dab75SAndroid Build Coastguard Worker #include "pn81a.h"
28*5c4dab75SAndroid Build Coastguard Worker 
29*5c4dab75SAndroid Build Coastguard Worker namespace android {
30*5c4dab75SAndroid Build Coastguard Worker namespace esed {
31*5c4dab75SAndroid Build Coastguard Worker namespace pn81a {
32*5c4dab75SAndroid Build Coastguard Worker 
33*5c4dab75SAndroid Build Coastguard Worker // HIDL
34*5c4dab75SAndroid Build Coastguard Worker using ::android::hardware::Status;
35*5c4dab75SAndroid Build Coastguard Worker 
36*5c4dab75SAndroid Build Coastguard Worker 
37*5c4dab75SAndroid Build Coastguard Worker // libapdu
38*5c4dab75SAndroid Build Coastguard Worker using ::android::CommandApdu;
39*5c4dab75SAndroid Build Coastguard Worker using ResponseApdu = ::android::ResponseApdu<const std::vector<uint8_t>>;
40*5c4dab75SAndroid Build Coastguard Worker 
41*5c4dab75SAndroid Build Coastguard Worker /**
42*5c4dab75SAndroid Build Coastguard Worker  * Reads a 32-bit integer from an iterator.
43*5c4dab75SAndroid Build Coastguard Worker  * @param first The first position to read from.
44*5c4dab75SAndroid Build Coastguard Worker  * @return A tuple of the value read and an iterator to one after the last position read from.
45*5c4dab75SAndroid Build Coastguard Worker  */
46*5c4dab75SAndroid Build Coastguard Worker template<typename InputIt>
readBigEndianInt32(InputIt first)47*5c4dab75SAndroid Build Coastguard Worker std::tuple<uint32_t, InputIt> readBigEndianInt32(InputIt first) {
48*5c4dab75SAndroid Build Coastguard Worker     uint32_t ret;
49*5c4dab75SAndroid Build Coastguard Worker     auto it = first;
50*5c4dab75SAndroid Build Coastguard Worker     ret  = *it++ << 24;
51*5c4dab75SAndroid Build Coastguard Worker     ret |= *it++ << 16;
52*5c4dab75SAndroid Build Coastguard Worker     ret |= *it++ <<  8;
53*5c4dab75SAndroid Build Coastguard Worker     ret |= *it++;
54*5c4dab75SAndroid Build Coastguard Worker     return {ret, it};
55*5c4dab75SAndroid Build Coastguard Worker }
56*5c4dab75SAndroid Build Coastguard Worker 
57*5c4dab75SAndroid Build Coastguard Worker /**
58*5c4dab75SAndroid Build Coastguard Worker  * Writes a 32-bit integer to the iterator in big-endian format.
59*5c4dab75SAndroid Build Coastguard Worker  * @param value The value to write.
60*5c4dab75SAndroid Build Coastguard Worker  * @param first The first position in the iterator.
61*5c4dab75SAndroid Build Coastguard Worker  * @return An iterator to one after the last position written to.
62*5c4dab75SAndroid Build Coastguard Worker  */
63*5c4dab75SAndroid Build Coastguard Worker template<typename OutputIt>
writeBigEndian(const uint32_t value,OutputIt first)64*5c4dab75SAndroid Build Coastguard Worker OutputIt writeBigEndian(const uint32_t value, OutputIt first) {
65*5c4dab75SAndroid Build Coastguard Worker     auto it = first;
66*5c4dab75SAndroid Build Coastguard Worker     *it++ = 0xff & (value >> 24);
67*5c4dab75SAndroid Build Coastguard Worker     *it++ = 0xff & (value >> 16);
68*5c4dab75SAndroid Build Coastguard Worker     *it++ = 0xff & (value >>  8);
69*5c4dab75SAndroid Build Coastguard Worker     *it++ = 0xff & value;
70*5c4dab75SAndroid Build Coastguard Worker     return it;
71*5c4dab75SAndroid Build Coastguard Worker }
72*5c4dab75SAndroid Build Coastguard Worker 
73*5c4dab75SAndroid Build Coastguard Worker /**
74*5c4dab75SAndroid Build Coastguard Worker  * Transceive a command with the eSE and perform common error checking. When the
75*5c4dab75SAndroid Build Coastguard Worker  * handler is called, it has been checked that the transmission to and reception
76*5c4dab75SAndroid Build Coastguard Worker  * from the eSE was successful and that the response is in a valid format.
77*5c4dab75SAndroid Build Coastguard Worker  */
78*5c4dab75SAndroid Build Coastguard Worker template<typename T, T OK, T FAILED>
79*5c4dab75SAndroid Build Coastguard Worker T transceive(::android::esed::EseInterface& ese, const CommandApdu& command,
80*5c4dab75SAndroid Build Coastguard Worker                   std::function<T(const ResponseApdu&)> handler = {}) {
81*5c4dab75SAndroid Build Coastguard Worker     // +1 for max size of extended response, +2 for status bytes
82*5c4dab75SAndroid Build Coastguard Worker     constexpr size_t MAX_RESPONSE_SIZE = std::numeric_limits<uint16_t>::max() + 1 + 2;
83*5c4dab75SAndroid Build Coastguard Worker     std::vector<uint8_t> responseBuffer(MAX_RESPONSE_SIZE);
84*5c4dab75SAndroid Build Coastguard Worker     const int ret = ese.transceive(command.vector(), responseBuffer);
85*5c4dab75SAndroid Build Coastguard Worker 
86*5c4dab75SAndroid Build Coastguard Worker     // Check eSE communication was successful
87*5c4dab75SAndroid Build Coastguard Worker     if (ret < 0) {
88*5c4dab75SAndroid Build Coastguard Worker         std::string errMsg = "Failed to transceive data between AP and eSE";
89*5c4dab75SAndroid Build Coastguard Worker         if (ese.error()) {
90*5c4dab75SAndroid Build Coastguard Worker             errMsg += " (" + std::to_string(ese.error_code()) + "): " + ese.error_message();
91*5c4dab75SAndroid Build Coastguard Worker         } else {
92*5c4dab75SAndroid Build Coastguard Worker             errMsg += ": reason unknown";
93*5c4dab75SAndroid Build Coastguard Worker         }
94*5c4dab75SAndroid Build Coastguard Worker         LOG(ERROR) << errMsg;
95*5c4dab75SAndroid Build Coastguard Worker         return FAILED;
96*5c4dab75SAndroid Build Coastguard Worker     }
97*5c4dab75SAndroid Build Coastguard Worker     const size_t recvd = static_cast<size_t>(ret);
98*5c4dab75SAndroid Build Coastguard Worker 
99*5c4dab75SAndroid Build Coastguard Worker     // Need to recalculate the maximum response size if this fails
100*5c4dab75SAndroid Build Coastguard Worker     if (recvd > MAX_RESPONSE_SIZE) {
101*5c4dab75SAndroid Build Coastguard Worker         LOG(ERROR) << "eSE response was longer than the buffer, check the buffer size.";
102*5c4dab75SAndroid Build Coastguard Worker         return FAILED;
103*5c4dab75SAndroid Build Coastguard Worker     }
104*5c4dab75SAndroid Build Coastguard Worker     responseBuffer.resize(recvd);
105*5c4dab75SAndroid Build Coastguard Worker 
106*5c4dab75SAndroid Build Coastguard Worker     // Check for ISO 7816-4 APDU response format errors
107*5c4dab75SAndroid Build Coastguard Worker     ResponseApdu apdu{responseBuffer};
108*5c4dab75SAndroid Build Coastguard Worker     if (!apdu.ok()) {
109*5c4dab75SAndroid Build Coastguard Worker         LOG(ERROR) << "eSE response was invalid.";
110*5c4dab75SAndroid Build Coastguard Worker         return FAILED;
111*5c4dab75SAndroid Build Coastguard Worker     }
112*5c4dab75SAndroid Build Coastguard Worker 
113*5c4dab75SAndroid Build Coastguard Worker     // Call handler if one was provided
114*5c4dab75SAndroid Build Coastguard Worker     if (handler) {
115*5c4dab75SAndroid Build Coastguard Worker         return handler(apdu);
116*5c4dab75SAndroid Build Coastguard Worker     }
117*5c4dab75SAndroid Build Coastguard Worker 
118*5c4dab75SAndroid Build Coastguard Worker     return OK;
119*5c4dab75SAndroid Build Coastguard Worker }
120*5c4dab75SAndroid Build Coastguard Worker 
121*5c4dab75SAndroid Build Coastguard Worker /**
122*5c4dab75SAndroid Build Coastguard Worker  * Checks that the amount of data in the response APDU matches the expected
123*5c4dab75SAndroid Build Coastguard Worker  * value.
124*5c4dab75SAndroid Build Coastguard Worker  */
125*5c4dab75SAndroid Build Coastguard Worker template<typename T, T OK, T FAILED>
checkLength(const ResponseApdu & apdu,const size_t size)126*5c4dab75SAndroid Build Coastguard Worker T checkLength(const ResponseApdu& apdu, const size_t size) {
127*5c4dab75SAndroid Build Coastguard Worker     if (apdu.dataSize() != size) {
128*5c4dab75SAndroid Build Coastguard Worker         LOG(ERROR) << "eSE response was the wrong length.";
129*5c4dab75SAndroid Build Coastguard Worker         return FAILED;
130*5c4dab75SAndroid Build Coastguard Worker     }
131*5c4dab75SAndroid Build Coastguard Worker     return OK;
132*5c4dab75SAndroid Build Coastguard Worker }
133*5c4dab75SAndroid Build Coastguard Worker 
134*5c4dab75SAndroid Build Coastguard Worker /**
135*5c4dab75SAndroid Build Coastguard Worker  * Checks that the response APDU does no encode an error and that the amount of
136*5c4dab75SAndroid Build Coastguard Worker  * data matches the expected value.
137*5c4dab75SAndroid Build Coastguard Worker  */
138*5c4dab75SAndroid Build Coastguard Worker template<typename T, T OK, T FAILED>
checkNoErrorAndLength(const ResponseApdu & apdu,const size_t size)139*5c4dab75SAndroid Build Coastguard Worker T checkNoErrorAndLength(const ResponseApdu& apdu, const size_t size) {
140*5c4dab75SAndroid Build Coastguard Worker     if (apdu.isError()) {
141*5c4dab75SAndroid Build Coastguard Worker         LOG(ERROR) << "eSE operation failed";
142*5c4dab75SAndroid Build Coastguard Worker         return FAILED;
143*5c4dab75SAndroid Build Coastguard Worker     }
144*5c4dab75SAndroid Build Coastguard Worker     return checkLength<T, OK, FAILED>(apdu, size);
145*5c4dab75SAndroid Build Coastguard Worker }
146*5c4dab75SAndroid Build Coastguard Worker 
147*5c4dab75SAndroid Build Coastguard Worker } // namespace android
148*5c4dab75SAndroid Build Coastguard Worker } // namespace esed
149*5c4dab75SAndroid Build Coastguard Worker } // namespace pn81a
150*5c4dab75SAndroid Build Coastguard Worker 
151*5c4dab75SAndroid Build Coastguard Worker #endif // ESED_PN81A_UTILS_H_
152