1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/apdu/apdu_command.h"
7 #include "base/check_op.h"
13 // APDU command data length is 2 bytes encoded in big endian order.
14 uint16_t ParseMessageLength(base::span<const uint8_t> message, size_t offset) {
15 DCHECK_GE(message.size(), offset + 2);
16 return (message[offset] << 8) | message[offset + 1];
21 absl::optional<ApduCommand> ApduCommand::CreateFromMessage(
22 base::span<const uint8_t> message) {
23 if (message.size() < kApduMinHeader || message.size() > kApduMaxLength)
26 uint8_t cla = message[0];
27 uint8_t ins = message[1];
28 uint8_t p1 = message[2];
29 uint8_t p2 = message[3];
31 size_t response_length = 0;
32 std::vector<uint8_t> data;
34 switch (message.size()) {
35 // No data present; no expected response.
38 // Invalid encoding sizes.
39 case kApduMinHeader + 1:
40 case kApduMinHeader + 2:
42 // No data present; response expected.
43 case kApduMinHeader + 3:
44 // Fifth byte must be 0.
47 response_length = ParseMessageLength(message, kApduCommandLengthOffset);
48 // Special case where response length of 0x0000 corresponds to 65536
49 // as defined in ISO7816-4.
50 if (response_length == 0)
51 response_length = kApduMaxResponseLength;
54 // Fifth byte must be 0.
57 auto data_length = ParseMessageLength(message, kApduCommandLengthOffset);
59 if (message.size() == data_length + kApduCommandDataOffset) {
60 // No response expected.
61 data.insert(data.end(), message.begin() + kApduCommandDataOffset,
63 } else if (message.size() == data_length + kApduCommandDataOffset + 2) {
64 // Maximum response size is stored in final 2 bytes.
65 data.insert(data.end(), message.begin() + kApduCommandDataOffset,
67 auto response_length_offset = kApduCommandDataOffset + data_length;
68 response_length = ParseMessageLength(message, response_length_offset);
69 // Special case where response length of 0x0000 corresponds to 65536
70 // as defined in ISO7816-4.
71 if (response_length == 0)
72 response_length = kApduMaxResponseLength;
79 return ApduCommand(cla, ins, p1, p2, response_length, std::move(data));
82 ApduCommand::ApduCommand() = default;
84 ApduCommand::ApduCommand(uint8_t cla,
88 size_t response_length,
89 std::vector<uint8_t> data)
94 response_length_(response_length),
95 data_(std::move(data)) {}
97 ApduCommand::ApduCommand(ApduCommand&& that) = default;
99 ApduCommand& ApduCommand::operator=(ApduCommand&& that) = default;
101 ApduCommand::~ApduCommand() = default;
103 std::vector<uint8_t> ApduCommand::GetEncodedCommand() const {
104 std::vector<uint8_t> encoded = {cla_, ins_, p1_, p2_};
106 // If data exists, request size (Lc) is encoded in 3 bytes, with the first
107 // byte always being null, and the other two bytes being a big-endian
108 // representation of the request size. If data length is 0, response size (Le)
109 // will be prepended with a null byte.
110 if (!data_.empty()) {
111 size_t data_length = data_.size();
113 encoded.push_back(0x0);
114 if (data_length > kApduMaxDataLength)
115 data_length = kApduMaxDataLength;
116 encoded.push_back((data_length >> 8) & 0xff);
117 encoded.push_back(data_length & 0xff);
118 encoded.insert(encoded.end(), data_.begin(), data_.begin() + data_length);
119 } else if (response_length_ > 0) {
120 encoded.push_back(0x0);
123 if (response_length_ > 0) {
124 size_t response_length = response_length_;
125 if (response_length > kApduMaxResponseLength)
126 response_length = kApduMaxResponseLength;
127 // A zero value represents a response length of 65,536 bytes.
128 encoded.push_back((response_length >> 8) & 0xff);
129 encoded.push_back(response_length & 0xff);