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 APDU_H_ 18*5c4dab75SAndroid Build Coastguard Worker #define APDU_H_ 19*5c4dab75SAndroid Build Coastguard Worker 20*5c4dab75SAndroid Build Coastguard Worker #include <cstddef> 21*5c4dab75SAndroid Build Coastguard Worker #include <cstdint> 22*5c4dab75SAndroid Build Coastguard Worker #include <iterator> 23*5c4dab75SAndroid Build Coastguard Worker #include <vector> 24*5c4dab75SAndroid Build Coastguard Worker 25*5c4dab75SAndroid Build Coastguard Worker namespace android { 26*5c4dab75SAndroid Build Coastguard Worker 27*5c4dab75SAndroid Build Coastguard Worker /** 28*5c4dab75SAndroid Build Coastguard Worker * Helper to build an APDU command. If a data section is needed, it is left empty with dataBegin 29*5c4dab75SAndroid Build Coastguard Worker * and dataEnd able to return iterators to where the data should be filled in. 30*5c4dab75SAndroid Build Coastguard Worker * 31*5c4dab75SAndroid Build Coastguard Worker * The command bytes are stored sequentially in the same manner as std::vector. 32*5c4dab75SAndroid Build Coastguard Worker */ 33*5c4dab75SAndroid Build Coastguard Worker class CommandApdu { 34*5c4dab75SAndroid Build Coastguard Worker public: CommandApdu(uint8_t cla,uint8_t ins,uint8_t p1,uint8_t p2)35*5c4dab75SAndroid Build Coastguard Worker CommandApdu(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2) 36*5c4dab75SAndroid Build Coastguard Worker : CommandApdu(cla, ins, p1, p2, 0, 0) {} 37*5c4dab75SAndroid Build Coastguard Worker CommandApdu(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, size_t lc, size_t le); 38*5c4dab75SAndroid Build Coastguard Worker 39*5c4dab75SAndroid Build Coastguard Worker using iterator = std::vector<uint8_t>::iterator; 40*5c4dab75SAndroid Build Coastguard Worker using const_iterator = std::vector<uint8_t>::const_iterator; 41*5c4dab75SAndroid Build Coastguard Worker begin()42*5c4dab75SAndroid Build Coastguard Worker iterator begin() { return mCommand.begin(); } end()43*5c4dab75SAndroid Build Coastguard Worker iterator end() { return mCommand.end(); } begin()44*5c4dab75SAndroid Build Coastguard Worker const_iterator begin() const { return mCommand.begin(); } end()45*5c4dab75SAndroid Build Coastguard Worker const_iterator end() const { return mCommand.end(); } 46*5c4dab75SAndroid Build Coastguard Worker dataBegin()47*5c4dab75SAndroid Build Coastguard Worker iterator dataBegin() { return mDataBegin; } dataEnd()48*5c4dab75SAndroid Build Coastguard Worker iterator dataEnd() { return mDataEnd; } dataBegin()49*5c4dab75SAndroid Build Coastguard Worker const_iterator dataBegin() const { return mDataBegin; } dataEnd()50*5c4dab75SAndroid Build Coastguard Worker const_iterator dataEnd() const { return mDataEnd; } 51*5c4dab75SAndroid Build Coastguard Worker size()52*5c4dab75SAndroid Build Coastguard Worker size_t size() const { return mCommand.size(); } dataSize()53*5c4dab75SAndroid Build Coastguard Worker size_t dataSize() const { return std::distance(mDataBegin, mDataEnd); } 54*5c4dab75SAndroid Build Coastguard Worker vector()55*5c4dab75SAndroid Build Coastguard Worker const std::vector<uint8_t>& vector() const { return mCommand; } 56*5c4dab75SAndroid Build Coastguard Worker 57*5c4dab75SAndroid Build Coastguard Worker private: 58*5c4dab75SAndroid Build Coastguard Worker std::vector<uint8_t> mCommand; 59*5c4dab75SAndroid Build Coastguard Worker std::vector<uint8_t>::iterator mDataBegin; 60*5c4dab75SAndroid Build Coastguard Worker std::vector<uint8_t>::iterator mDataEnd; 61*5c4dab75SAndroid Build Coastguard Worker }; 62*5c4dab75SAndroid Build Coastguard Worker 63*5c4dab75SAndroid Build Coastguard Worker /** 64*5c4dab75SAndroid Build Coastguard Worker * Helper to deconstruct a response APDU. This wraps a reference to an iterable byte container. 65*5c4dab75SAndroid Build Coastguard Worker */ 66*5c4dab75SAndroid Build Coastguard Worker template<typename T> 67*5c4dab75SAndroid Build Coastguard Worker class ResponseApdu { 68*5c4dab75SAndroid Build Coastguard Worker static constexpr size_t STATUS_SIZE = 2; 69*5c4dab75SAndroid Build Coastguard Worker static constexpr uint8_t BYTES_AVAILABLE = 0x61; 70*5c4dab75SAndroid Build Coastguard Worker static constexpr uint8_t SW1_WARNING_NON_VOLATILE_MEMORY_UNCHANGED = 0x62; 71*5c4dab75SAndroid Build Coastguard Worker static constexpr uint8_t SW1_WARNING_NON_VOLATILE_MEMORY_CHANGED = 0x63; 72*5c4dab75SAndroid Build Coastguard Worker static constexpr uint8_t SW1_FIRST_EXECUTION_ERROR = 0x64; 73*5c4dab75SAndroid Build Coastguard Worker static constexpr uint8_t SW1_LAST_EXECUTION_ERROR = 0x66; 74*5c4dab75SAndroid Build Coastguard Worker static constexpr uint8_t SW1_FIRST_CHECKING_ERROR = 0x67; 75*5c4dab75SAndroid Build Coastguard Worker static constexpr uint8_t SW1_LAST_CHECKING_ERROR = 0x6f; 76*5c4dab75SAndroid Build Coastguard Worker 77*5c4dab75SAndroid Build Coastguard Worker public: ResponseApdu(const T & data)78*5c4dab75SAndroid Build Coastguard Worker ResponseApdu(const T& data) : mData(data) {} 79*5c4dab75SAndroid Build Coastguard Worker ok()80*5c4dab75SAndroid Build Coastguard Worker bool ok() const { 81*5c4dab75SAndroid Build Coastguard Worker return static_cast<size_t>( 82*5c4dab75SAndroid Build Coastguard Worker std::distance(std::begin(mData), std::end(mData))) >= STATUS_SIZE; 83*5c4dab75SAndroid Build Coastguard Worker } 84*5c4dab75SAndroid Build Coastguard Worker sw1()85*5c4dab75SAndroid Build Coastguard Worker uint8_t sw1() const { return *(std::end(mData) - 2); } sw2()86*5c4dab75SAndroid Build Coastguard Worker uint8_t sw2() const { return *(std::end(mData) - 1); } status()87*5c4dab75SAndroid Build Coastguard Worker uint16_t status() const { return (static_cast<uint16_t>(sw1()) << 8) | sw2(); } 88*5c4dab75SAndroid Build Coastguard Worker remainingBytes()89*5c4dab75SAndroid Build Coastguard Worker int8_t remainingBytes() const { return sw1() == BYTES_AVAILABLE ? sw2() : 0; } 90*5c4dab75SAndroid Build Coastguard Worker isWarning()91*5c4dab75SAndroid Build Coastguard Worker bool isWarning() const { 92*5c4dab75SAndroid Build Coastguard Worker const uint8_t sw1 = this->sw1(); 93*5c4dab75SAndroid Build Coastguard Worker return sw1 == SW1_WARNING_NON_VOLATILE_MEMORY_UNCHANGED 94*5c4dab75SAndroid Build Coastguard Worker || sw1 == SW1_WARNING_NON_VOLATILE_MEMORY_CHANGED; 95*5c4dab75SAndroid Build Coastguard Worker } isExecutionError()96*5c4dab75SAndroid Build Coastguard Worker bool isExecutionError() const { 97*5c4dab75SAndroid Build Coastguard Worker const uint8_t sw1 = this->sw1(); 98*5c4dab75SAndroid Build Coastguard Worker return sw1 >= SW1_FIRST_EXECUTION_ERROR && sw1 <= SW1_LAST_EXECUTION_ERROR; 99*5c4dab75SAndroid Build Coastguard Worker } isCheckingError()100*5c4dab75SAndroid Build Coastguard Worker bool isCheckingError() const { 101*5c4dab75SAndroid Build Coastguard Worker const uint8_t sw1 = this->sw1(); 102*5c4dab75SAndroid Build Coastguard Worker return sw1 >= SW1_FIRST_CHECKING_ERROR && sw1 <= SW1_LAST_CHECKING_ERROR; 103*5c4dab75SAndroid Build Coastguard Worker } isError()104*5c4dab75SAndroid Build Coastguard Worker bool isError() const { return isExecutionError() || isCheckingError(); } 105*5c4dab75SAndroid Build Coastguard Worker dataBegin()106*5c4dab75SAndroid Build Coastguard Worker auto dataBegin() const { return std::begin(mData); } dataEnd()107*5c4dab75SAndroid Build Coastguard Worker auto dataEnd() const { return std::end(mData) - STATUS_SIZE; } 108*5c4dab75SAndroid Build Coastguard Worker dataSize()109*5c4dab75SAndroid Build Coastguard Worker size_t dataSize() const { return std::distance(dataBegin(), dataEnd()); } 110*5c4dab75SAndroid Build Coastguard Worker 111*5c4dab75SAndroid Build Coastguard Worker private: 112*5c4dab75SAndroid Build Coastguard Worker const T& mData; 113*5c4dab75SAndroid Build Coastguard Worker }; 114*5c4dab75SAndroid Build Coastguard Worker 115*5c4dab75SAndroid Build Coastguard Worker } // namespace android 116*5c4dab75SAndroid Build Coastguard Worker 117*5c4dab75SAndroid Build Coastguard Worker #endif // APDU_H_ 118