Home | History | Annotate | Download | only in apdu
      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:
     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 
     42     iterator begin() { return mCommand.begin(); }
     43     iterator end() { return mCommand.end(); }
     44     const_iterator begin() const { return mCommand.begin(); }
     45     const_iterator end() const { return mCommand.end(); }
     46 
     47     iterator dataBegin() { return mDataBegin; }
     48     iterator dataEnd() { return mDataEnd; }
     49     const_iterator dataBegin() const { return mDataBegin; }
     50     const_iterator dataEnd() const { return mDataEnd; }
     51 
     52     size_t size() const { return mCommand.size(); }
     53     size_t dataSize() const { return std::distance(mDataBegin, mDataEnd); }
     54 
     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:
     78     ResponseApdu(const T& data) : mData(data) {}
     79 
     80     bool ok() const {
     81         return static_cast<size_t>(
     82                 std::distance(std::begin(mData), std::end(mData))) >= STATUS_SIZE;
     83     }
     84 
     85     uint8_t sw1() const { return *(std::end(mData) - 2); }
     86     uint8_t sw2() const { return *(std::end(mData) - 1); }
     87     uint16_t status() const { return (static_cast<uint16_t>(sw1()) << 8) | sw2(); }
     88 
     89     int8_t remainingBytes() const { return sw1() == BYTES_AVAILABLE ? sw2() : 0; }
     90 
     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     }
     96     bool isExecutionError() const {
     97         const uint8_t sw1 = this->sw1();
     98         return sw1 >= SW1_FIRST_EXECUTION_ERROR && sw1 <= SW1_LAST_EXECUTION_ERROR;
     99     }
    100     bool isCheckingError() const {
    101         const uint8_t sw1 = this->sw1();
    102         return sw1 >= SW1_FIRST_CHECKING_ERROR && sw1 <= SW1_LAST_CHECKING_ERROR;
    103     }
    104     bool isError() const { return isExecutionError() || isCheckingError(); }
    105 
    106     auto dataBegin() const { return std::begin(mData); }
    107     auto dataEnd() const { return std::end(mData) - STATUS_SIZE; }
    108 
    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