|
23 | 23 | #include "pcsc-cpp/pcsc-cpp.hpp" |
24 | 24 | #include "pcsc-cpp/pcsc-cpp-utils.hpp" |
25 | 25 |
|
26 | | -#include <sstream> |
| 26 | +#include <algorithm> |
27 | 27 | #include <iomanip> |
| 28 | +#include <sstream> |
28 | 29 |
|
29 | 30 | using namespace pcsc_cpp; |
30 | 31 | using namespace std::string_literals; |
31 | 32 |
|
32 | | -#ifdef HIBYTE |
33 | | -#undef HIBYTE |
34 | | -#endif |
35 | | -#ifdef LOBYTE |
36 | | -#undef LOBYTE |
37 | | -#endif |
38 | | - |
39 | | -constexpr byte_type HIBYTE(size_t w) noexcept |
40 | | -{ |
41 | | - return static_cast<byte_type>((w >> 8) & 0xff); |
42 | | -} |
43 | | -constexpr byte_type LOBYTE(size_t w) noexcept |
44 | | -{ |
45 | | - return static_cast<byte_type>(w & 0xff); |
46 | | -} |
47 | | - |
48 | 33 | namespace |
49 | 34 | { |
50 | 35 |
|
51 | | -const byte_type DER_SEQUENCE_TYPE_TAG = 0x30; |
52 | | -const byte_type DER_TWO_BYTE_LENGTH = 0x82; |
53 | | - |
54 | 36 | class UnexpectedResponseError : public Error |
55 | 37 | { |
56 | 38 | public: |
@@ -93,68 +75,25 @@ void transmitApduWithExpectedResponse(const SmartCard& card, const CommandApdu& |
93 | 75 | } |
94 | 76 | } |
95 | 77 |
|
96 | | -size_t readDataLengthFromAsn1(const SmartCard& card) |
97 | | -{ |
98 | | - // p1 - offset size first byte, 0 |
99 | | - // p2 - offset size second byte, 0 |
100 | | - // le - number of bytes to read, need 4 bytes from start for length |
101 | | - const CommandApdu readBinary4Bytes {0x00, 0xb0, 0x00, 0x00, 0x04}; |
102 | | - |
103 | | - auto response = card.transmit(readBinary4Bytes); |
104 | | - |
105 | | - // Verify expected DER header, first byte must be SEQUENCE. |
106 | | - if (response.data[0] != DER_SEQUENCE_TYPE_TAG) { |
107 | | - // TODO: more specific exception |
108 | | - THROW(Error, |
109 | | - "readDataLengthFromAsn1(): First byte must be SEQUENCE (0x30), but is "s |
110 | | - + int2hexstr(response.data[0])); |
111 | | - } |
112 | | - |
113 | | - // TODO: support other lenghts besides 2. |
114 | | - // Assume 2-byte length, so second byte must be 0x82. |
115 | | - if (response.data[1] != DER_TWO_BYTE_LENGTH) { |
116 | | - // TODO: more specific exception |
117 | | - THROW(Error, |
118 | | - "readDataLengthFromAsn1(): Second byte must be two-byte length indicator "s |
119 | | - "(0x82), but is "s |
120 | | - + int2hexstr(response.data[1])); |
121 | | - } |
122 | | - |
123 | | - // Read 2-byte length field at offset 2 and 3 and add the 4 DER length bytes. |
124 | | - const auto length = size_t((response.data[2] << 8) + response.data[3] + 4); |
125 | | - if (length < 128 || length > 0x0f00) { |
126 | | - // TODO: more specific exception |
127 | | - THROW(Error, |
128 | | - "readDataLengthFromAsn1(): Unexpected data length in DER header: "s |
129 | | - + std::to_string(length)); |
130 | | - } |
131 | | - |
132 | | - return length; |
133 | | -} |
134 | | - |
135 | | -byte_vector readBinary(const SmartCard& card, const size_t length, byte_type blockLength) |
| 78 | +byte_vector readBinary(const SmartCard& card, const uint16_t length, byte_type blockLength) |
136 | 79 | { |
137 | | - auto lengthCounter = length; |
138 | | - auto resultBytes = byte_vector {}; |
139 | | - |
140 | | - for (size_t offset = 0; lengthCounter != 0; |
141 | | - offset += blockLength, lengthCounter -= blockLength) { |
142 | | - |
143 | | - if (blockLength > lengthCounter) { |
144 | | - blockLength = byte_type(lengthCounter); |
| 80 | + byte_vector resultBytes; |
| 81 | + resultBytes.reserve(length); |
| 82 | + while (resultBytes.size() < length) { |
| 83 | + byte_type chunk = byte_type(std::min<size_t>(length - resultBytes.size(), blockLength)); |
| 84 | + auto response = card.transmit(CommandApdu::readBinary(uint16_t(resultBytes.size()), chunk)); |
| 85 | + if (chunk > 0 && response.data.size() != chunk) { |
| 86 | + THROW(Error, |
| 87 | + "readBinary(): Invalid length received: "s + std::to_string(response.data.size()) |
| 88 | + + " excpected: " + std::to_string(chunk)); |
145 | 89 | } |
146 | | - |
147 | | - CommandApdu readBinary {0x00, 0xb0, HIBYTE(offset), LOBYTE(offset), blockLength}; |
148 | | - auto response = card.transmit(readBinary); |
149 | | - |
150 | 90 | resultBytes.insert(resultBytes.end(), response.data.cbegin(), response.data.cend()); |
151 | 91 | } |
152 | | - |
153 | 92 | if (resultBytes.size() != length) { |
154 | | - // TODO: more specific exception |
155 | | - THROW(Error, "readBinary(): Invalid length: "s + std::to_string(resultBytes.size())); |
| 93 | + THROW(Error, |
| 94 | + "readBinary(): Invalid length received: "s + std::to_string(resultBytes.size()) |
| 95 | + + " excpected: " + std::to_string(length)); |
156 | 96 | } |
157 | | - |
158 | 97 | return resultBytes; |
159 | 98 | } |
160 | 99 |
|
|
0 commit comments