[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / components / apdu / apdu_command.cc
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.
4
5 #include "components/apdu/apdu_command.h"
6
7 #include "base/check_op.h"
8
9 namespace apdu {
10
11 namespace {
12
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];
17 }
18
19 }  // namespace
20
21 absl::optional<ApduCommand> ApduCommand::CreateFromMessage(
22     base::span<const uint8_t> message) {
23   if (message.size() < kApduMinHeader || message.size() > kApduMaxLength)
24     return absl::nullopt;
25
26   uint8_t cla = message[0];
27   uint8_t ins = message[1];
28   uint8_t p1 = message[2];
29   uint8_t p2 = message[3];
30
31   size_t response_length = 0;
32   std::vector<uint8_t> data;
33
34   switch (message.size()) {
35     // No data present; no expected response.
36     case kApduMinHeader:
37       break;
38     // Invalid encoding sizes.
39     case kApduMinHeader + 1:
40     case kApduMinHeader + 2:
41       return absl::nullopt;
42     // No data present; response expected.
43     case kApduMinHeader + 3:
44       // Fifth byte must be 0.
45       if (message[4] != 0)
46         return absl::nullopt;
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;
52       break;
53     default:
54       // Fifth byte must be 0.
55       if (message[4] != 0)
56         return absl::nullopt;
57       auto data_length = ParseMessageLength(message, kApduCommandLengthOffset);
58
59       if (message.size() == data_length + kApduCommandDataOffset) {
60         // No response expected.
61         data.insert(data.end(), message.begin() + kApduCommandDataOffset,
62                     message.end());
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,
66                     message.end() - 2);
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;
73       } else {
74         return absl::nullopt;
75       }
76       break;
77   }
78
79   return ApduCommand(cla, ins, p1, p2, response_length, std::move(data));
80 }
81
82 ApduCommand::ApduCommand() = default;
83
84 ApduCommand::ApduCommand(uint8_t cla,
85                          uint8_t ins,
86                          uint8_t p1,
87                          uint8_t p2,
88                          size_t response_length,
89                          std::vector<uint8_t> data)
90     : cla_(cla),
91       ins_(ins),
92       p1_(p1),
93       p2_(p2),
94       response_length_(response_length),
95       data_(std::move(data)) {}
96
97 ApduCommand::ApduCommand(ApduCommand&& that) = default;
98
99 ApduCommand& ApduCommand::operator=(ApduCommand&& that) = default;
100
101 ApduCommand::~ApduCommand() = default;
102
103 std::vector<uint8_t> ApduCommand::GetEncodedCommand() const {
104   std::vector<uint8_t> encoded = {cla_, ins_, p1_, p2_};
105
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();
112
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);
121   }
122
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);
130   }
131   return encoded;
132 }
133
134 }  // namespace apdu