22template <
typename TransportT>
25 explicit Device(TransportT& transport) noexcept : session_(transport), t1_(transport) {}
31 std::uint8_t* rx, std::size_t rx_cap,
32 std::size_t* rx_len_out,
33 std::uint32_t timeout_ms)
noexcept {
34 return session_.TransceiveRaw(tx, tx_len, rx, rx_cap, rx_len_out, timeout_ms);
53 scp03_wrap_cap_ = cap;
70 [[nodiscard]]
Error TransmitApdu(
const std::uint8_t* capdu, std::size_t capdu_len, std::uint8_t* rapdu_buf,
71 std::size_t rapdu_cap, std::size_t* rapdu_len,
72 std::uint32_t timeout_ms)
noexcept {
73 if (rapdu_len ==
nullptr) {
80 if (scp03_.Failed()) {
83 if (!scp03_.IsOpen()) {
84 return t1_.ExchangeInformation(capdu, capdu_len, rapdu_buf, rapdu_cap, rapdu_len, timeout_ms);
89 std::size_t wrapped_len = 0;
90 Error e = scp03_.WrapCommand(capdu, capdu_len, scp03_wrap_, scp03_wrap_cap_, &wrapped_len);
94 e = t1_.ExchangeInformation(scp03_wrap_, wrapped_len, rapdu_buf, rapdu_cap, rapdu_len, timeout_ms);
101 return scp03_.UnwrapResponse(rapdu_buf, *rapdu_len, rapdu_buf, rapdu_cap, rapdu_len);
111 std::uint32_t timeout_ms)
noexcept {
113 std::size_t capdu_len = 0;
118 return TransmitApdu(capdu, capdu_len, rapdu_buf, rapdu_cap, rapdu_len, timeout_ms);
127 std::uint32_t timeout_ms)
noexcept {
129 std::size_t capdu_len = 0;
134 return TransmitApdu(capdu, capdu_len, rapdu_buf, rapdu_cap, rapdu_len, timeout_ms);
138 if (out ==
nullptr) {
141 std::uint8_t capdu[32]{};
142 std::size_t capdu_len = 0;
147 std::uint8_t rapdu[64]{};
148 std::size_t rapdu_len = 0;
149 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
156 [[nodiscard]]
Error GetRandom(std::uint16_t bytes_requested, std::uint8_t* out, std::size_t out_cap,
157 std::size_t* out_len, std::uint32_t timeout_ms)
noexcept {
158 if (out_len ==
nullptr) {
162 std::uint8_t capdu[32]{};
163 std::size_t capdu_len = 0;
169 std::size_t rapdu_len = 0;
170 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
178 std::uint32_t timeout_ms)
noexcept {
179 if (free_bytes ==
nullptr) {
182 std::uint8_t capdu[32]{};
183 std::size_t capdu_len = 0;
188 std::uint8_t rapdu[64]{};
189 std::size_t rapdu_len = 0;
190 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
198 bool has_offset, std::uint16_t offset,
bool has_file_length,
199 std::uint16_t file_length, std::uint32_t timeout_ms)
noexcept {
201 std::size_t capdu_len = 0;
203 capdu,
sizeof(capdu), &capdu_len);
207 std::uint8_t rapdu[64]{};
208 std::size_t rapdu_len = 0;
209 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
213 const std::uint8_t* payload =
nullptr;
214 std::size_t payload_len = 0;
224 bool has_length, std::uint16_t length, std::uint8_t* out, std::size_t out_cap,
225 std::size_t* out_len, std::uint32_t timeout_ms)
noexcept {
226 if (out_len ==
nullptr) {
230 std::uint8_t capdu[64]{};
231 std::size_t capdu_len = 0;
238 std::size_t rapdu_len = 0;
239 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
247 std::uint8_t capdu[32]{};
248 std::size_t capdu_len = 0;
253 std::uint8_t rapdu[64]{};
254 std::size_t rapdu_len = 0;
255 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
259 const std::uint8_t* payload =
nullptr;
260 std::size_t payload_len = 0;
270 std::uint32_t timeout_ms)
noexcept {
271 if (exists ==
nullptr) {
275 std::uint8_t capdu[32]{};
276 std::size_t capdu_len = 0;
281 std::uint8_t rapdu[96]{};
282 std::size_t rapdu_len = 0;
283 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
291 std::size_t* out_len, std::uint32_t timeout_ms)
noexcept {
292 return ReadObject(key_id,
false, 0U,
false, 0U, out, out_cap, out_len, timeout_ms);
296 std::uint32_t timeout_ms)
noexcept {
297 std::uint8_t capdu[64]{};
298 std::size_t capdu_len = 0;
303 std::uint8_t rapdu[64]{};
304 std::size_t rapdu_len = 0;
305 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
309 const std::uint8_t* payload =
nullptr;
310 std::size_t payload_len = 0;
320 const std::uint8_t* digest, std::size_t digest_len,
321 std::uint8_t* signature_out, std::size_t signature_cap,
322 std::size_t* signature_len, std::uint32_t timeout_ms)
noexcept {
323 if (signature_len ==
nullptr) {
327 std::uint8_t capdu[256]{};
328 std::size_t capdu_len = 0;
334 std::size_t rapdu_len = 0;
335 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
339 return cmd::ParseDataTag1(rapdu, rapdu_len, signature_out, signature_cap, signature_len);
343 const std::uint8_t* digest, std::size_t digest_len,
344 const std::uint8_t* signature, std::size_t signature_len,
345 bool* verified, std::uint32_t timeout_ms)
noexcept {
346 if (verified ==
nullptr) {
350 std::uint8_t capdu[384]{};
351 std::size_t capdu_len = 0;
353 sizeof(capdu), &capdu_len);
357 std::uint8_t rapdu[96]{};
358 std::size_t rapdu_len = 0;
359 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
372 std::uint32_t timeout_ms)
noexcept {
373 std::uint8_t capdu[80]{};
374 std::size_t capdu_len = 0;
379 std::uint8_t rapdu[32]{};
380 std::size_t rapdu_len = 0;
381 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
385 const std::uint8_t* payload =
nullptr;
386 std::size_t payload_len = 0;
401 std::size_t in_len, std::uint8_t* out, std::size_t out_cap, std::size_t* out_len,
402 std::uint32_t timeout_ms)
noexcept {
403 if (out_len ==
nullptr) {
407 if (in ==
nullptr || out ==
nullptr || in_len == 0U || (in_len % 16U) != 0U) {
410 std::uint8_t capdu[80]{};
411 std::size_t capdu_len = 0;
416 std::uint8_t rapdu[48]{};
417 std::size_t rapdu_len = 0;
418 e =
TransmitApdu(capdu, capdu_len, rapdu,
sizeof(rapdu), &rapdu_len, timeout_ms);
430 std::size_t wrapped_len, std::uint8_t* out, std::size_t out_cap,
431 std::size_t* out_len, std::uint32_t timeout_ms)
noexcept {
435 std::uint32_t timeout_ms;
437 Ctx ctx{
this, kek_id, timeout_ms};
438 auto decrypt = [](
const std::uint8_t in[16], std::uint8_t outb[16],
void* v) ->
Error {
439 auto* c =
static_cast<Ctx*
>(v);
441 const Error e = c->self->
CipherAesEcb(c->id,
true, in, 16U, outb, 16U, &n, c->timeout_ms);
447 return rfc3394::Unwrap(wrapped, wrapped_len, out, out_cap, out_len, decrypt, &ctx);
457 std::uint8_t* scp03_wrap_{
nullptr};
458 std::size_t scp03_wrap_cap_{0};
Definition se050_device.hpp:23
Error SelectDefaultIoTApplet(std::uint8_t *rapdu_buf, std::size_t rapdu_cap, std::size_t *rapdu_len, std::uint32_t timeout_ms) noexcept
SELECT the default IoT applet (applet::kDefaultIoTAppletAid, short Le).
Definition se050_device.hpp:110
Error WriteAesKey(const cmd::ObjectId &object_id, const std::uint8_t *key, std::size_t key_len, std::uint32_t timeout_ms) noexcept
Write a persistent AESKey (AN12413 WriteSymmKey, P1_AES).
Definition se050_device.hpp:371
Device(TransportT &transport) noexcept
Definition se050_device.hpp:25
Error ReadPublicEcKey(const cmd::ObjectId &key_id, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:290
T1Session< TransportT > & T1() noexcept
ISO 7816-3 T=1 session bound to the same transport as SessionRef.
Definition se050_device.hpp:40
Error TransmitApdu(const std::uint8_t *capdu, std::size_t capdu_len, std::uint8_t *rapdu_buf, std::size_t rapdu_cap, std::size_t *rapdu_len, std::uint32_t timeout_ms) noexcept
Transmit a C-APDU (already serialized) and receive the R-APDU INF bytes.
Definition se050_device.hpp:70
const scp03::Session< TransportT > & Scp03() const noexcept
Definition se050_device.hpp:45
Error CipherAesEcb(const cmd::ObjectId &key_id, bool decrypt, const std::uint8_t *in, std::size_t in_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len, std::uint32_t timeout_ms) noexcept
One-shot AES-ECB (AN12413 CipherOneShot, AES_ECB_NOPAD).
Definition se050_device.hpp:400
Error GetVersion(cmd::VersionInfo *out, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:137
Error GetRandom(std::uint16_t bytes_requested, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:156
Session< TransportT > & SessionRef() noexcept
Definition se050_device.hpp:450
scp03::Session< TransportT > & Scp03() noexcept
SCP03 session. Handshake uses T=1 directly; wrapped APDUs go through TransmitApdu.
Definition se050_device.hpp:44
Error UnwrapAes256Rfc3394(const cmd::ObjectId &kek_id, const std::uint8_t *wrapped, std::size_t wrapped_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len, std::uint32_t timeout_ms) noexcept
RFC 3394 unwrap of an AES-256 CEK using kek_id as the wrapping key.
Definition se050_device.hpp:429
const Session< TransportT > & SessionRef() const noexcept
Definition se050_device.hpp:451
Error EcdsaVerify(const cmd::ObjectId &key_id, cmd::EcdsaAlgo algo, const std::uint8_t *digest, std::size_t digest_len, const std::uint8_t *signature, std::size_t signature_len, bool *verified, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:342
bool EnsureInitialized() noexcept
Definition se050_device.hpp:27
Error TransceiveRaw(const std::uint8_t *tx, std::size_t tx_len, std::uint8_t *rx, std::size_t rx_cap, std::size_t *rx_len_out, std::uint32_t timeout_ms) noexcept
Raw I²C exchange (legacy / bring-up); prefer T1 for SE050 T=1 blocks.
Definition se050_device.hpp:30
void BindScp03WrapScratch(std::uint8_t *buf, std::size_t cap) noexcept
Bind caller-owned wrap workspace (CM4: D2 .se_apdu_scratch, not a task stack).
Definition se050_device.hpp:51
Error CheckObjectExists(const cmd::ObjectId &object_id, bool *exists, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:269
Error WriteBinary(const cmd::ObjectId &object_id, const std::uint8_t *data, std::size_t data_len, bool has_offset, std::uint16_t offset, bool has_file_length, std::uint16_t file_length, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:197
const T1Session< TransportT > & T1() const noexcept
Definition se050_device.hpp:41
Error DeleteSecureObject(const cmd::ObjectId &object_id, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:246
Error HardwareReset() noexcept
Definition se050_device.hpp:37
Error GenerateEcKeyPair(const cmd::ObjectId &object_id, cmd::EcCurve curve, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:295
Error ReadObject(const cmd::ObjectId &object_id, bool has_offset, std::uint16_t offset, bool has_length, std::uint16_t length, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:223
Error GetFreeMemory(cmd::MemoryType memory_type, std::uint16_t *free_bytes, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:177
Error EcdsaSign(const cmd::ObjectId &key_id, cmd::EcdsaAlgo algo, const std::uint8_t *digest, std::size_t digest_len, std::uint8_t *signature_out, std::size_t signature_cap, std::size_t *signature_len, std::uint32_t timeout_ms) noexcept
Definition se050_device.hpp:319
Error SelectCardManager(std::uint8_t *rapdu_buf, std::size_t rapdu_cap, std::size_t *rapdu_len, std::uint32_t timeout_ms) noexcept
SELECT the GlobalPlatform Card Manager (ISD) for PUT KEY.
Definition se050_device.hpp:126
Transport-facing session (no owned buffers).
Definition se050_session.hpp:25
Stateful T=1 session bound to a concrete I²C transport.
Definition se050_t1_session.hpp:101
SCP03 session bound to a T=1 transport.
Definition se050_scp03.hpp:398
bool IsSuccess(const StatusWords &sw) noexcept
Return true when SW1 == 0x90 and SW2 == 0x00.
Definition se050_apdu.hpp:161
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
constexpr std::uint8_t kCardManagerAid[]
GlobalPlatform Card Manager / ISD AID (8 bytes).
Definition se050_applet.hpp:40
constexpr std::uint8_t kDefaultIoTAppletAid[]
NXP Plug & Trust SE05x IoT applet AID (16 bytes).
Definition se050_applet.hpp:27
Error BuildSelectDefaultIot(std::uint8_t *out, std::size_t cap, std::size_t *out_len) noexcept
Build SELECT (CLA=0x00, INS=0xA4, P1=0x04, P2=0x00) for kDefaultIoTAppletAid.
Definition se050_applet.hpp:51
Error BuildSelectCardManager(std::uint8_t *out, std::size_t cap, std::size_t *out_len) noexcept
Build SELECT for the Card Manager / ISD (kCardManagerAid).
Definition se050_applet.hpp:60
Error BuildEcdsaSign(const ObjectId &key_id, EcdsaAlgo algo, const std::uint8_t *digest, std::size_t digest_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:282
Error ParseDataTag1(const std::uint8_t *rapdu, std::size_t rapdu_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:399
Error BuildCipherOneShot(const ObjectId &key_id, bool decrypt, 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
Definition se050_commands.hpp:230
Error BuildGetRandom(std::uint16_t random_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:93
Error BuildGetFreeMemory(MemoryType memory_type, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:108
Error ParseFreeMemory(const std::uint8_t *rapdu, std::size_t rapdu_len, std::uint16_t *free_bytes) noexcept
Definition se050_commands.hpp:380
Error ParseVerifyResult(const std::uint8_t *rapdu, std::size_t rapdu_len, bool *verified) noexcept
Definition se050_commands.hpp:422
Error BuildReadObject(const ObjectId &object_id, bool has_offset, std::uint16_t offset, bool has_length, std::uint16_t length, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:254
MemoryType
Definition se050_commands.hpp:57
Error BuildWriteBinary(const ObjectId &object_id, const std::uint8_t *data, std::size_t data_len, bool has_offset, std::uint16_t offset, bool has_file_length, std::uint16_t file_length, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:177
EcCurve
Definition se050_commands.hpp:63
Error ParseVersionInfo(const std::uint8_t *rapdu, std::size_t rapdu_len, VersionInfo *out) noexcept
Definition se050_commands.hpp:357
std::array< std::uint8_t, 4 > ObjectId
Definition se050_commands.hpp:55
Error BuildGetVersion(std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:87
Error ParseObjectExistsResult(const std::uint8_t *rapdu, std::size_t rapdu_len, bool *exists) noexcept
Definition se050_commands.hpp:442
EcdsaAlgo
Definition se050_commands.hpp:71
Error BuildWriteAesKey(const ObjectId &object_id, const std::uint8_t *key, std::size_t key_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:211
Error BuildGenerateEcKeyPair(const ObjectId &object_id, EcCurve curve, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:158
Error BuildDeleteSecureObject(const ObjectId &object_id, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:124
Error BuildCheckObjectExists(const ObjectId &object_id, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:139
Error BuildEcdsaVerify(const ObjectId &key_id, EcdsaAlgo algo, const std::uint8_t *digest, std::size_t digest_len, const std::uint8_t *signature, std::size_t signature_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
Definition se050_commands.hpp:306
Error Unwrap(const std::uint8_t *wrapped, std::size_t wrapped_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len, AesBlockFn decrypt, void *ctx) noexcept
RFC 3394 unwrap. wrapped_len must be 8*(n+1) with n >= 2.
Definition se050_rfc3394.hpp:52
constexpr std::size_t kWrapScratchBytes
Minimum wrap workspace, enough for short APDUs (CM4: D2 .se_apdu_scratch, not task stack).
Definition se050_scp03.hpp:40
Definition se050_apdu.hpp:15
Error
Definition se050_types.hpp:14
constexpr std::size_t kMaxApduCommandBytes
Definition se050_types.hpp:40
constexpr std::size_t kMaxApduResponseBytes
Definition se050_types.hpp:42
SE050 applet selection helpers (ISO 7816-4 SELECT by DF name / AID).
Typed SE050 command builders/parsers for a core management/object subset.
RFC 3394 AES Key Wrap / Unwrap with a caller-supplied AES-128 block.
GlobalPlatform SCP03 session over an existing T=1 I²C link.
Low-level session: owns no buffers; forwards transceive to transport.
ISO/IEC 7816-3 T=1 block protocol for NXP SE050 T=1 over I²C (EDC = CRC-16).
Shared types, limits, and error codes for the HF-SE050 driver.
Parsed status words from a response APDU.
Definition se050_apdu.hpp:18
Definition se050_commands.hpp:79