• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef APDU_H_
18 #define APDU_H_
19 
20 #include <cstddef>
21 #include <cstdint>
22 #include <iterator>
23 #include <vector>
24 
25 namespace android {
26 
27 /**
28  * Helper to build an APDU command. If a data section is needed, it is left empty with dataBegin
29  * and dataEnd able to return iterators to where the data should be filled in.
30  *
31  * The command bytes are stored sequentially in the same manner as std::vector.
32  */
33 class CommandApdu {
34 public:
CommandApdu(uint8_t cla,uint8_t ins,uint8_t p1,uint8_t p2)35     CommandApdu(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2)
36             : CommandApdu(cla, ins, p1, p2, 0, 0) {}
37     CommandApdu(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, size_t lc, size_t le);
38 
39     using iterator = std::vector<uint8_t>::iterator;
40     using const_iterator = std::vector<uint8_t>::const_iterator;
41 
begin()42     iterator begin() { return mCommand.begin(); }
end()43     iterator end() { return mCommand.end(); }
begin()44     const_iterator begin() const { return mCommand.begin(); }
end()45     const_iterator end() const { return mCommand.end(); }
46 
dataBegin()47     iterator dataBegin() { return mDataBegin; }
dataEnd()48     iterator dataEnd() { return mDataEnd; }
dataBegin()49     const_iterator dataBegin() const { return mDataBegin; }
dataEnd()50     const_iterator dataEnd() const { return mDataEnd; }
51 
size()52     size_t size() const { return mCommand.size(); }
dataSize()53     size_t dataSize() const { return std::distance(mDataBegin, mDataEnd); }
54 
vector()55     const std::vector<uint8_t>& vector() const { return mCommand; }
56 
57 private:
58     std::vector<uint8_t> mCommand;
59     std::vector<uint8_t>::iterator mDataBegin;
60     std::vector<uint8_t>::iterator mDataEnd;
61 };
62 
63 /**
64  * Helper to deconstruct a response APDU. This wraps a reference to an iterable byte container.
65  */
66 template<typename T>
67 class ResponseApdu {
68     static constexpr size_t STATUS_SIZE = 2;
69     static constexpr uint8_t BYTES_AVAILABLE = 0x61;
70     static constexpr uint8_t SW1_WARNING_NON_VOLATILE_MEMORY_UNCHANGED = 0x62;
71     static constexpr uint8_t SW1_WARNING_NON_VOLATILE_MEMORY_CHANGED = 0x63;
72     static constexpr uint8_t SW1_FIRST_EXECUTION_ERROR = 0x64;
73     static constexpr uint8_t SW1_LAST_EXECUTION_ERROR = 0x66;
74     static constexpr uint8_t SW1_FIRST_CHECKING_ERROR = 0x67;
75     static constexpr uint8_t SW1_LAST_CHECKING_ERROR = 0x6f;
76 
77 public:
ResponseApdu(const T & data)78     ResponseApdu(const T& data) : mData(data) {}
79 
ok()80     bool ok() const {
81         return static_cast<size_t>(
82                 std::distance(std::begin(mData), std::end(mData))) >= STATUS_SIZE;
83     }
84 
sw1()85     uint8_t sw1() const { return *(std::end(mData) - 2); }
sw2()86     uint8_t sw2() const { return *(std::end(mData) - 1); }
status()87     uint16_t status() const { return (static_cast<uint16_t>(sw1()) << 8) | sw2(); }
88 
remainingBytes()89     int8_t remainingBytes() const { return sw1() == BYTES_AVAILABLE ? sw2() : 0; }
90 
isWarning()91     bool isWarning() const {
92         const uint8_t sw1 = this->sw1();
93         return sw1 == SW1_WARNING_NON_VOLATILE_MEMORY_UNCHANGED
94             || sw1 == SW1_WARNING_NON_VOLATILE_MEMORY_CHANGED;
95     }
isExecutionError()96     bool isExecutionError() const {
97         const uint8_t sw1 = this->sw1();
98         return sw1 >= SW1_FIRST_EXECUTION_ERROR && sw1 <= SW1_LAST_EXECUTION_ERROR;
99     }
isCheckingError()100     bool isCheckingError() const {
101         const uint8_t sw1 = this->sw1();
102         return sw1 >= SW1_FIRST_CHECKING_ERROR && sw1 <= SW1_LAST_CHECKING_ERROR;
103     }
isError()104     bool isError() const { return isExecutionError() || isCheckingError(); }
105 
dataBegin()106     auto dataBegin() const { return std::begin(mData); }
dataEnd()107     auto dataEnd() const { return std::end(mData) - STATUS_SIZE; }
108 
dataSize()109     size_t dataSize() const { return std::distance(dataBegin(), dataEnd()); }
110 
111 private:
112     const T& mData;
113 };
114 
115 } // namespace android
116 
117 #endif // APDU_H_
118