SE050 Driver
API reference
Loading...
Searching...
No Matches
se050_apdu.hpp
Go to the documentation of this file.
1
7#pragma once
8
9#include "se050_types.hpp"
10
11#include <cstddef>
12#include <cstdint>
13#include <cstring>
14
15namespace se050::apdu {
16
19 std::uint8_t sw1{0};
20 std::uint8_t sw2{0};
21};
22
23[[nodiscard]] inline Error BuildCaseShort(std::uint8_t cla, std::uint8_t ins, std::uint8_t p1,
24 std::uint8_t p2, const std::uint8_t* data,
25 std::uint8_t data_len, bool le_present, std::uint8_t le,
26 std::uint8_t* out, std::size_t out_cap,
27 std::size_t* out_len) noexcept;
28
46[[nodiscard]] inline Error BuildCase4Extended(std::uint8_t cla, std::uint8_t ins, std::uint8_t p1,
47 std::uint8_t p2, const std::uint8_t* data,
48 std::size_t data_len, std::uint8_t* out,
49 std::size_t out_cap, std::size_t* out_len) noexcept {
50 if (out_len == nullptr) {
52 }
53 *out_len = 0;
54 /* SE050C2 on this desk answers short APDUs (SELECT 0x9000) and rejects
55 * Bertin-style extended Lc/Le for the same INS (GetVersion). Prefer
56 * short CASE 2/4 whenever the payload fits in one Lc byte. */
57 if (data_len <= 255U) {
58 if (data_len == 0U) {
59 if (out_cap < 5U) {
61 }
62 out[0] = cla;
63 out[1] = ins;
64 out[2] = p1;
65 out[3] = p2;
66 out[4] = 0x00U; /* CASE 2 Le */
67 *out_len = 5U;
68 return Error::Ok;
69 }
70 return BuildCaseShort(cla, ins, p1, p2, data, static_cast<std::uint8_t>(data_len), true, 0x00U,
71 out, out_cap, out_len);
72 }
73 constexpr std::size_t kHeader = 7U; /* CLA.. + 00 LcHi LcLo */
74 constexpr std::size_t kLeExt = 2U; /* LeHi LeLo (case 4E: Lc already extended) */
75 if (data_len > (kMaxApduCommandBytes - kHeader - kLeExt)) {
77 }
78 const std::size_t need = kHeader + data_len + kLeExt;
79 if (need > out_cap) {
81 }
82 std::size_t i = 0;
83 out[i++] = cla;
84 out[i++] = ins;
85 out[i++] = p1;
86 out[i++] = p2;
87 out[i++] = 0x00;
88 out[i++] = static_cast<std::uint8_t>((data_len >> 8) & 0xFFU);
89 out[i++] = static_cast<std::uint8_t>(data_len & 0xFFU);
90 if (data_len > 0U && data != nullptr) {
91 std::memcpy(out + i, data, data_len);
92 i += data_len;
93 }
94 out[i++] = 0x00;
95 out[i++] = 0x00; /* Le = 00 00: Ne = 65536 (ISO/IEC 7816-4 5.1) */
96 *out_len = i;
97 return Error::Ok;
98}
99
106[[nodiscard]] inline Error BuildCaseShort(std::uint8_t cla, std::uint8_t ins, std::uint8_t p1,
107 std::uint8_t p2, const std::uint8_t* data,
108 std::uint8_t data_len, bool le_present, std::uint8_t le,
109 std::uint8_t* out, std::size_t out_cap,
110 std::size_t* out_len) noexcept {
111 if (out_len == nullptr) {
113 }
114 *out_len = 0;
115 const std::size_t need = 5U + data_len + (le_present ? 1U : 0U);
116 if (need > out_cap) {
118 }
119 std::size_t i = 0;
120 out[i++] = cla;
121 out[i++] = ins;
122 out[i++] = p1;
123 out[i++] = p2;
124 out[i++] = data_len;
125 if (data_len > 0U && data != nullptr) {
126 std::memcpy(out + i, data, data_len);
127 i += data_len;
128 }
129 if (le_present) {
130 out[i++] = le;
131 }
132 *out_len = i;
133 return Error::Ok;
134}
135
144[[nodiscard]] inline Error ParseResponse(const std::uint8_t* rsp, std::size_t rsp_len,
145 const std::uint8_t** data_out, std::size_t* data_len_out,
146 StatusWords* sw_out) noexcept {
147 if (data_out == nullptr || data_len_out == nullptr || sw_out == nullptr) {
149 }
150 if (rsp_len < 2U) {
151 return Error::Protocol;
152 }
153 *data_out = rsp;
154 *data_len_out = rsp_len - 2U;
155 sw_out->sw1 = rsp[rsp_len - 2U];
156 sw_out->sw2 = rsp[rsp_len - 1U];
157 return Error::Ok;
158}
159
161[[nodiscard]] inline bool IsSuccess(const StatusWords& sw) noexcept {
162 return sw.sw1 == 0x90U && sw.sw2 == 0x00U;
163}
164
166[[nodiscard]] inline bool IsMoreData(const StatusWords& sw) noexcept { return sw.sw1 == 0x61U; }
167
168} // namespace se050::apdu
Definition se050_apdu.hpp:15
Error BuildCase4Extended(std::uint8_t cla, std::uint8_t ins, std::uint8_t p1, std::uint8_t p2, const std::uint8_t *data, std::size_t data_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Build a CASE 4 command APDU with extended length encoding.
Definition se050_apdu.hpp:46
bool IsSuccess(const StatusWords &sw) noexcept
Return true when SW1 == 0x90 and SW2 == 0x00.
Definition se050_apdu.hpp:161
bool IsMoreData(const StatusWords &sw) noexcept
SW1 == 0x61 — more data available via GET RESPONSE (common GlobalPlatform pattern).
Definition se050_apdu.hpp:166
Error BuildCaseShort(std::uint8_t cla, std::uint8_t ins, std::uint8_t p1, std::uint8_t p2, const std::uint8_t *data, std::uint8_t data_len, bool le_present, std::uint8_t le, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Build a CASE 3/4 short command when data_len ≤ 255 and a 1-byte Le is enough.
Definition se050_apdu.hpp:106
Error ParseResponse(const std::uint8_t *rsp, std::size_t rsp_len, const std::uint8_t **data_out, std::size_t *data_len_out, StatusWords *sw_out) noexcept
Parse a simple R-APDU: optional response data followed by SW1 SW2.
Definition se050_apdu.hpp:144
Error
Definition se050_types.hpp:14
constexpr std::size_t kMaxApduCommandBytes
Definition se050_types.hpp:40
Shared types, limits, and error codes for the HF-SE050 driver.
Parsed status words from a response APDU.
Definition se050_apdu.hpp:18
std::uint8_t sw2
Definition se050_apdu.hpp:20
std::uint8_t sw1
Definition se050_apdu.hpp:19