apdu_command.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/apdu/apdu_command.h"
  5. #include "base/check_op.h"
  6. namespace apdu {
  7. namespace {
  8. // APDU command data length is 2 bytes encoded in big endian order.
  9. uint16_t ParseMessageLength(base::span<const uint8_t> message, size_t offset) {
  10. DCHECK_GE(message.size(), offset + 2);
  11. return (message[offset] << 8) | message[offset + 1];
  12. }
  13. } // namespace
  14. absl::optional<ApduCommand> ApduCommand::CreateFromMessage(
  15. base::span<const uint8_t> message) {
  16. if (message.size() < kApduMinHeader || message.size() > kApduMaxLength)
  17. return absl::nullopt;
  18. uint8_t cla = message[0];
  19. uint8_t ins = message[1];
  20. uint8_t p1 = message[2];
  21. uint8_t p2 = message[3];
  22. size_t response_length = 0;
  23. std::vector<uint8_t> data;
  24. switch (message.size()) {
  25. // No data present; no expected response.
  26. case kApduMinHeader:
  27. break;
  28. // Invalid encoding sizes.
  29. case kApduMinHeader + 1:
  30. case kApduMinHeader + 2:
  31. return absl::nullopt;
  32. // No data present; response expected.
  33. case kApduMinHeader + 3:
  34. // Fifth byte must be 0.
  35. if (message[4] != 0)
  36. return absl::nullopt;
  37. response_length = ParseMessageLength(message, kApduCommandLengthOffset);
  38. // Special case where response length of 0x0000 corresponds to 65536
  39. // as defined in ISO7816-4.
  40. if (response_length == 0)
  41. response_length = kApduMaxResponseLength;
  42. break;
  43. default:
  44. // Fifth byte must be 0.
  45. if (message[4] != 0)
  46. return absl::nullopt;
  47. auto data_length = ParseMessageLength(message, kApduCommandLengthOffset);
  48. if (message.size() == data_length + kApduCommandDataOffset) {
  49. // No response expected.
  50. data.insert(data.end(), message.begin() + kApduCommandDataOffset,
  51. message.end());
  52. } else if (message.size() == data_length + kApduCommandDataOffset + 2) {
  53. // Maximum response size is stored in final 2 bytes.
  54. data.insert(data.end(), message.begin() + kApduCommandDataOffset,
  55. message.end() - 2);
  56. auto response_length_offset = kApduCommandDataOffset + data_length;
  57. response_length = ParseMessageLength(message, response_length_offset);
  58. // Special case where response length of 0x0000 corresponds to 65536
  59. // as defined in ISO7816-4.
  60. if (response_length == 0)
  61. response_length = kApduMaxResponseLength;
  62. } else {
  63. return absl::nullopt;
  64. }
  65. break;
  66. }
  67. return ApduCommand(cla, ins, p1, p2, response_length, std::move(data));
  68. }
  69. ApduCommand::ApduCommand() = default;
  70. ApduCommand::ApduCommand(uint8_t cla,
  71. uint8_t ins,
  72. uint8_t p1,
  73. uint8_t p2,
  74. size_t response_length,
  75. std::vector<uint8_t> data)
  76. : cla_(cla),
  77. ins_(ins),
  78. p1_(p1),
  79. p2_(p2),
  80. response_length_(response_length),
  81. data_(std::move(data)) {}
  82. ApduCommand::ApduCommand(ApduCommand&& that) = default;
  83. ApduCommand& ApduCommand::operator=(ApduCommand&& that) = default;
  84. ApduCommand::~ApduCommand() = default;
  85. std::vector<uint8_t> ApduCommand::GetEncodedCommand() const {
  86. std::vector<uint8_t> encoded = {cla_, ins_, p1_, p2_};
  87. // If data exists, request size (Lc) is encoded in 3 bytes, with the first
  88. // byte always being null, and the other two bytes being a big-endian
  89. // representation of the request size. If data length is 0, response size (Le)
  90. // will be prepended with a null byte.
  91. if (!data_.empty()) {
  92. size_t data_length = data_.size();
  93. encoded.push_back(0x0);
  94. if (data_length > kApduMaxDataLength)
  95. data_length = kApduMaxDataLength;
  96. encoded.push_back((data_length >> 8) & 0xff);
  97. encoded.push_back(data_length & 0xff);
  98. encoded.insert(encoded.end(), data_.begin(), data_.begin() + data_length);
  99. } else if (response_length_ > 0) {
  100. encoded.push_back(0x0);
  101. }
  102. if (response_length_ > 0) {
  103. size_t response_length = response_length_;
  104. if (response_length > kApduMaxResponseLength)
  105. response_length = kApduMaxResponseLength;
  106. // A zero value represents a response length of 65,536 bytes.
  107. encoded.push_back((response_length >> 8) & 0xff);
  108. encoded.push_back(response_length & 0xff);
  109. }
  110. return encoded;
  111. }
  112. } // namespace apdu