mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-02-11 12:18:38 -05:00
Add challenge-response support for Nitrokey 3 (#9631)
Co-authored-by: Szczepan Zalega <szczepan@nitrokey.com>
This commit is contained in:
parent
f30604c6f6
commit
33b740ddd0
@ -242,23 +242,68 @@ namespace
|
|||||||
if (rv == SCARD_S_SUCCESS) {
|
if (rv == SCARD_S_SUCCESS) {
|
||||||
// Write to and read from the card
|
// Write to and read from the card
|
||||||
// pioRecvPci is nullptr because we do not expect any PCI response header
|
// pioRecvPci is nullptr because we do not expect any PCI response header
|
||||||
|
const SCUINT dwRecvBufferSize = dwRecvLength;
|
||||||
rv = SCardTransmit(handle, pioSendPci, pbSendBuffer, dwSendLength, nullptr, pbRecvBuffer, &dwRecvLength);
|
rv = SCardTransmit(handle, pioSendPci, pbSendBuffer, dwSendLength, nullptr, pbRecvBuffer, &dwRecvLength);
|
||||||
|
|
||||||
|
if (dwRecvLength < 2) {
|
||||||
|
// Any valid response should be at least 2 bytes (response status)
|
||||||
|
// However the protocol itself could fail
|
||||||
|
return SCARD_E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t SW1 = pbRecvBuffer[dwRecvLength - 2];
|
||||||
|
// Check for the MoreDataAvailable SW1 code. If present, send GetResponse command repeatedly, until success
|
||||||
|
// SW, or filling the receiving buffer.
|
||||||
|
if (SW1 == SW_MORE_DATA_HIGH) {
|
||||||
|
while (true) {
|
||||||
|
if (dwRecvBufferSize < dwRecvLength) {
|
||||||
|
// No free buffer space remaining
|
||||||
|
return SCARD_E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
// Overwrite Status Word in the receiving buffer
|
||||||
|
dwRecvLength -= 2;
|
||||||
|
SCUINT dwRecvLength_sr = dwRecvBufferSize - dwRecvLength; // at least 2 bytes for SW are available
|
||||||
|
const uint8_t bRecvDataSize =
|
||||||
|
qBound(static_cast<SCUINT>(0), dwRecvLength_sr - 2, static_cast<SCUINT>(255));
|
||||||
|
uint8_t pbSendBuffer_sr[] = {CLA_ISO, INS_GET_RESPONSE, 0, 0, bRecvDataSize};
|
||||||
|
rv = SCardTransmit(handle,
|
||||||
|
pioSendPci,
|
||||||
|
pbSendBuffer_sr,
|
||||||
|
sizeof pbSendBuffer_sr,
|
||||||
|
nullptr,
|
||||||
|
pbRecvBuffer + dwRecvLength,
|
||||||
|
&dwRecvLength_sr);
|
||||||
|
|
||||||
|
// Check if any new data are received. Break if the smart card's status is other than success,
|
||||||
|
// or no new bytes were received.
|
||||||
|
if (!(rv == SCARD_S_SUCCESS && dwRecvLength_sr >= 2)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwRecvLength += dwRecvLength_sr;
|
||||||
|
SW1 = pbRecvBuffer[dwRecvLength - 2];
|
||||||
|
// Break the loop if there is no continuation status
|
||||||
|
if (SW1 != SW_MORE_DATA_HIGH) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rv == SCARD_S_SUCCESS) {
|
if (rv == SCARD_S_SUCCESS) {
|
||||||
if (dwRecvLength < 2) {
|
if (dwRecvLength < 2) {
|
||||||
// Any valid response should be at least 2 bytes (response status)
|
// Any valid response should be at least 2 bytes (response status)
|
||||||
// However the protocol itself could fail
|
// However the protocol itself could fail
|
||||||
rv = SCARD_E_UNEXPECTED;
|
rv = SCARD_E_UNEXPECTED;
|
||||||
} else {
|
} else {
|
||||||
if (pbRecvBuffer[dwRecvLength - 2] == SW_OK_HIGH && pbRecvBuffer[dwRecvLength - 1] == SW_OK_LOW) {
|
const uint8_t SW_HIGH = pbRecvBuffer[dwRecvLength - 2];
|
||||||
|
const uint8_t SW_LOW = pbRecvBuffer[dwRecvLength - 1];
|
||||||
|
if (SW_HIGH == SW_OK_HIGH && SW_LOW == SW_OK_LOW) {
|
||||||
rv = SCARD_S_SUCCESS;
|
rv = SCARD_S_SUCCESS;
|
||||||
} else if (pbRecvBuffer[dwRecvLength - 2] == SW_PRECOND_HIGH
|
} else if (SW_HIGH == SW_PRECOND_HIGH && SW_LOW == SW_PRECOND_LOW) {
|
||||||
&& pbRecvBuffer[dwRecvLength - 1] == SW_PRECOND_LOW) {
|
|
||||||
// This happens if the key requires eg. a button press or if the applet times out
|
// This happens if the key requires eg. a button press or if the applet times out
|
||||||
// Solution: Re-present the card to the reader
|
// Solution: Re-present the card to the reader
|
||||||
rv = SCARD_W_CARD_NOT_AUTHENTICATED;
|
rv = SCARD_W_CARD_NOT_AUTHENTICATED;
|
||||||
} else if ((pbRecvBuffer[dwRecvLength - 2] == SW_NOTFOUND_HIGH
|
} else if ((SW_HIGH == SW_NOTFOUND_HIGH && SW_LOW == SW_NOTFOUND_LOW) || SW_HIGH == SW_UNSUP_HIGH) {
|
||||||
&& pbRecvBuffer[dwRecvLength - 1] == SW_NOTFOUND_LOW)
|
|
||||||
|| pbRecvBuffer[dwRecvLength - 2] == SW_UNSUP_HIGH) {
|
|
||||||
// This happens eg. during a select command when the AID is not found
|
// This happens eg. during a select command when the AID is not found
|
||||||
rv = SCARD_E_FILE_NOT_FOUND;
|
rv = SCARD_E_FILE_NOT_FOUND;
|
||||||
} else {
|
} else {
|
||||||
@ -285,9 +330,10 @@ namespace
|
|||||||
auto pbSendBuffer = new uint8_t[5 + handle.second.size()];
|
auto pbSendBuffer = new uint8_t[5 + handle.second.size()];
|
||||||
memcpy(pbSendBuffer, pbSendBuffer_head, 5);
|
memcpy(pbSendBuffer, pbSendBuffer_head, 5);
|
||||||
memcpy(pbSendBuffer + 5, handle.second.constData(), handle.second.size());
|
memcpy(pbSendBuffer + 5, handle.second.constData(), handle.second.size());
|
||||||
uint8_t pbRecvBuffer[12] = {
|
// Give it more space in case custom implementations have longer answer to select
|
||||||
|
uint8_t pbRecvBuffer[64] = {
|
||||||
0}; // 3 bytes version, 1 byte program counter, other stuff for various implementations, 2 bytes status
|
0}; // 3 bytes version, 1 byte program counter, other stuff for various implementations, 2 bytes status
|
||||||
SCUINT dwRecvLength = 12;
|
SCUINT dwRecvLength = sizeof pbRecvBuffer;
|
||||||
|
|
||||||
auto rv = transmit(handle.first, pbSendBuffer, 5 + handle.second.size(), pbRecvBuffer, dwRecvLength);
|
auto rv = transmit(handle.first, pbSendBuffer, 5 + handle.second.size(), pbRecvBuffer, dwRecvLength);
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#define CLA_ISO 0x00
|
#define CLA_ISO 0x00
|
||||||
#define INS_SELECT 0xA4
|
#define INS_SELECT 0xA4
|
||||||
|
#define INS_GET_RESPONSE 0xC0
|
||||||
#define SEL_APP_AID 0x04
|
#define SEL_APP_AID 0x04
|
||||||
#define INS_API_REQ 0x01
|
#define INS_API_REQ 0x01
|
||||||
#define INS_STATUS 0x03
|
#define INS_STATUS 0x03
|
||||||
@ -37,6 +38,7 @@
|
|||||||
#define SW_NOTFOUND_HIGH 0x6A
|
#define SW_NOTFOUND_HIGH 0x6A
|
||||||
#define SW_NOTFOUND_LOW 0x82
|
#define SW_NOTFOUND_LOW 0x82
|
||||||
#define SW_UNSUP_HIGH 0x6D
|
#define SW_UNSUP_HIGH 0x6D
|
||||||
|
#define SW_MORE_DATA_HIGH 0x61
|
||||||
|
|
||||||
typedef QPair<SCARDHANDLE, QByteArray> SCardAID;
|
typedef QPair<SCARDHANDLE, QByteArray> SCardAID;
|
||||||
|
|
||||||
@ -75,6 +77,7 @@ private:
|
|||||||
// and also for compatible third-party ones. They will be tried one by one.
|
// and also for compatible third-party ones. They will be tried one by one.
|
||||||
const QList<QByteArray> m_aid_codes = {
|
const QList<QByteArray> m_aid_codes = {
|
||||||
QByteArrayLiteral("\xA0\x00\x00\x05\x27\x20\x01"), // Yubico Yubikey
|
QByteArrayLiteral("\xA0\x00\x00\x05\x27\x20\x01"), // Yubico Yubikey
|
||||||
|
QByteArrayLiteral("\xA0\x00\x00\x05\x27\x21\x01"), // Yubico Yubikey OATH AID / Nitrokey 3 Secrets App
|
||||||
QByteArrayLiteral("\xA0\x00\x00\x06\x17\x00\x07\x53\x4E\xAF\x01") // Fidesmo development
|
QByteArrayLiteral("\xA0\x00\x00\x06\x17\x00\x07\x53\x4E\xAF\x01") // Fidesmo development
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -109,7 +112,10 @@ private:
|
|||||||
{QByteArrayLiteral("\x3B\x80\x80\x01\x01"), "Fidesmo Card 2.0"},
|
{QByteArrayLiteral("\x3B\x80\x80\x01\x01"), "Fidesmo Card 2.0"},
|
||||||
{QByteArrayLiteral("\x3B\x8A\x80\x01\x00\x31\xC1\x73\xC8\x40\x00\x00\x90\x00\x90"), "VivoKey Apex"},
|
{QByteArrayLiteral("\x3B\x8A\x80\x01\x00\x31\xC1\x73\xC8\x40\x00\x00\x90\x00\x90"), "VivoKey Apex"},
|
||||||
{QByteArrayLiteral("\x3B\x8D\x80\x01\x00\x31\xC1\x73\xC8\x40\x00\x52\xA5\x10\x00\x90\x00\x70"),
|
{QByteArrayLiteral("\x3B\x8D\x80\x01\x00\x31\xC1\x73\xC8\x40\x00\x52\xA5\x10\x00\x90\x00\x70"),
|
||||||
"Dangerous Things FlexSecure"}};
|
"Dangerous Things FlexSecure"},
|
||||||
|
{QByteArrayLiteral("\x3b\x8f\x01\x80\x5d\x4e\x69\x74\x72\x6f\x6b\x65\x79\x00\x00\x00\x00\x00\x6a"),
|
||||||
|
"Nitrokey 3"},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_YUBIKEY_INTERFACE_PCSC_H
|
#endif // KEEPASSX_YUBIKEY_INTERFACE_PCSC_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user