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