-
Notifications
You must be signed in to change notification settings - Fork 27
Clear PIN from buffer on destruction #138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -30,6 +30,9 @@ | |||||
| #include <vector> | ||||||
|
|
||||||
| // The rule of five (C++ Core guidelines C.21). | ||||||
| #define PCSC_CPP_DEFAULT_MOVE(Class) \ | ||||||
| Class(Class&&) = default; \ | ||||||
| Class& operator=(Class&&) = default | ||||||
| #define PCSC_CPP_DISABLE_COPY(Class) \ | ||||||
| Class(const Class&) = delete; \ | ||||||
| Class& operator=(const Class&) = delete | ||||||
|
|
@@ -119,6 +122,7 @@ struct ResponseApdu | |||||
| } | ||||||
| }; | ||||||
|
|
||||||
| struct VerifyApdu; | ||||||
| /** | ||||||
| * Struct that wraps command APDUs. | ||||||
| * | ||||||
|
|
@@ -162,6 +166,8 @@ struct CommandApdu | |||||
| d.push_back(le); | ||||||
| } | ||||||
|
|
||||||
| virtual ~CommandApdu() noexcept = default; | ||||||
|
|
||||||
| constexpr operator const byte_vector&() const { return d; } | ||||||
|
|
||||||
| /** | ||||||
|
|
@@ -213,9 +219,45 @@ struct CommandApdu | |||||
| return {0x00, 0xb0, byte_type(pos >> 8), byte_type(pos), le}; | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * A helper function to create a VERIFY command APDU. | ||||||
| * The ISO 7816-4 Section 6.12 VERIFY command has the form: | ||||||
| * CLA = 0x00 | ||||||
| * INS = 0x20 | ||||||
| * P1 = Only P1=’00’ is valid (other values are RFU) | ||||||
| * P2 = Qualifier of the reference data | ||||||
| * Lc and Data field = Empty or verification data | ||||||
| * Le = Empty | ||||||
| */ | ||||||
| static PCSC_CPP_CONSTEXPR_VECTOR VerifyApdu verify(byte_type p2, byte_vector&& pin, | ||||||
| size_t paddingLength, | ||||||
| pcsc_cpp::byte_type paddingChar); | ||||||
|
|
||||||
| byte_vector d; | ||||||
| }; | ||||||
|
|
||||||
| struct VerifyApdu final : public CommandApdu | ||||||
| { | ||||||
| using CommandApdu::CommandApdu; | ||||||
| PCSC_CPP_DISABLE_COPY(VerifyApdu); | ||||||
| PCSC_CPP_DEFAULT_MOVE(VerifyApdu); | ||||||
| constexpr ~VerifyApdu() noexcept final { std::fill(d.begin(), d.end(), byte_type(0)); } | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use We should use
(and elsewhere where we erase the pin). |
||||||
| }; | ||||||
|
|
||||||
| PCSC_CPP_CONSTEXPR_VECTOR VerifyApdu CommandApdu::verify(byte_type p2, byte_vector&& pin, | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be |
||||||
| size_t paddingLength, | ||||||
| pcsc_cpp::byte_type paddingChar) | ||||||
| { | ||||||
| if (!pin.empty() && pin.capacity() < paddingLength + 5) { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will fail if For example, assume And by ES.45: Avoid “magic constants”; use symbolic constants I would recommend replacing 5 with |
||||||
| throw std::invalid_argument( | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's use the
Suggested change
|
||||||
| "PIN buffer does not have enough capacity to pad without reallocation"); | ||||||
| } | ||||||
| if (pin.size() < paddingLength) { | ||||||
| pin.insert(pin.end(), paddingLength - pin.size(), paddingChar); | ||||||
| } | ||||||
| return {0x00, 0x20, 0x00, p2, std::move(pin)}; | ||||||
| } | ||||||
|
|
||||||
| /** Opaque class that wraps the PC/SC smart card resources like card handle and I/O protocol. */ | ||||||
| class CardImpl; | ||||||
|
|
||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,33 +87,19 @@ inline pcsc_cpp::byte_vector readFile(const pcsc_cpp::SmartCard::Session& sessio | |
| return readBinary(session, pcsc_cpp::toSW(*size.begin, *(size.begin + 1)), blockLength); | ||
| } | ||
|
|
||
| PCSC_CPP_CONSTEXPR_VECTOR inline pcsc_cpp::byte_vector | ||
| addPaddingToPin(pcsc_cpp::byte_vector&& pin, size_t paddingLength, pcsc_cpp::byte_type paddingChar) | ||
| { | ||
| if (pin.capacity() < paddingLength) { | ||
| THROW(ProgrammingError, | ||
| "PIN buffer does not have enough capacity to pad without reallocation"); | ||
| } | ||
| if (pin.size() < paddingLength) { | ||
| pin.insert(pin.end(), paddingLength - pin.size(), paddingChar); | ||
| } | ||
| return std::move(pin); | ||
| } | ||
|
|
||
| inline void verifyPin(const pcsc_cpp::SmartCard::Session& session, pcsc_cpp::byte_type p2, | ||
| pcsc_cpp::byte_vector&& pin, ElectronicID::PinMinMaxLength pinMinMax, | ||
| pcsc_cpp::byte_type paddingChar) | ||
| { | ||
| pcsc_cpp::ResponseApdu response; | ||
|
|
||
| if (session.readerHasPinPad()) { | ||
| const pcsc_cpp::CommandApdu verifyPin { | ||
| 0x00, 0x20, 0x00, p2, pcsc_cpp::byte_vector(pinMinMax.second, paddingChar)}; | ||
| response = session.transmitCTL(verifyPin, 0, pinMinMax.first); | ||
| response = session.transmitCTL( | ||
| pcsc_cpp::CommandApdu::verify(p2, std::move(pin), pinMinMax.second, paddingChar), 0, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the caller accidentally provides a non-empty PIN for the pin-pad reader case, this change causes it to be embedded into the APDU. Previous code with the dummy padding-only PIN was safer. Or am I mistaken here? |
||
| pinMinMax.first); | ||
| } else { | ||
| const pcsc_cpp::CommandApdu verifyPin { | ||
| 0x00, 0x20, 0x00, p2, addPaddingToPin(std::move(pin), pinMinMax.second, paddingChar)}; | ||
| response = session.transmit(verifyPin); | ||
| response = session.transmit( | ||
| pcsc_cpp::CommandApdu::verify(p2, std::move(pin), pinMinMax.second, paddingChar)); | ||
| } | ||
|
|
||
| // NOTE: in case card-specific error handling logic is needed, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding
PCSC_CPP_CONSTEXPR_VECTOR, can and should polymorphic types (with a virtual destructor) beconstexpr?CommandApduandVerifyApduare polymorphic now and I'm not sureconstexprreally applies to them any more.On the other hand, we could avoid making
CommandApdudestructor virtual as the temporaryVerifyApduobject is deleted insideverifyPin()directly, not through aCommandApdupointer or reference.