1 /*!
2  * \copyright Copyright (c) 2014-2021 Governikus GmbH & Co. KG, Germany
3  */
4 
5 #include "ResponseApdu.h"
6 
7 #include <QLoggingCategory>
8 #include <QtEndian>
9 
10 using namespace governikus;
11 
Q_DECLARE_LOGGING_CATEGORY(card)12 Q_DECLARE_LOGGING_CATEGORY(card)
13 
14 ResponseApdu::ResponseApdu(StatusCode pStatusCode)
15 	: Apdu(QByteArray())
16 {
17 	char buffer[2];
18 	qToBigEndian<quint16>(Enum<StatusCode>::getValue(pStatusCode), buffer);
19 	ResponseApdu::setBuffer(QByteArray(buffer, 2));
20 }
21 
22 
ResponseApdu(const QByteArray & pBuffer)23 ResponseApdu::ResponseApdu(const QByteArray& pBuffer)
24 	: Apdu(pBuffer)
25 {
26 }
27 
28 
setBuffer(const QByteArray & pBuffer)29 void ResponseApdu::setBuffer(const QByteArray& pBuffer)
30 {
31 	mBuffer = pBuffer;
32 }
33 
34 
getData() const35 QByteArray ResponseApdu::getData() const
36 {
37 	if (length() < RETURN_CODE_LENGTH)
38 	{
39 		return QByteArray();
40 	}
41 
42 	return mBuffer.left(getDataLength());
43 }
44 
45 
getDataLength() const46 int ResponseApdu::getDataLength() const
47 {
48 	return length() - RETURN_CODE_LENGTH;
49 }
50 
51 
getReturnCode() const52 StatusCode ResponseApdu::getReturnCode() const
53 {
54 	if (mBuffer.isEmpty())
55 	{
56 		return StatusCode::EMPTY;
57 	}
58 
59 	const int returnCodeAsInt = getReturnCodeAsHex().toInt(nullptr, 16);
60 	return Enum<StatusCode>::isValue(returnCodeAsInt) ? StatusCode(returnCodeAsInt) : StatusCode::INVALID;
61 }
62 
63 
getReturnCodeAsHex() const64 QByteArray ResponseApdu::getReturnCodeAsHex() const
65 {
66 	return mBuffer.right(RETURN_CODE_LENGTH).toHex();
67 }
68 
69 
getRetryCounter() const70 int ResponseApdu::getRetryCounter() const
71 {
72 	StatusCode statusCode = getReturnCode();
73 	if (statusCode == StatusCode::SUCCESS)
74 	{
75 		return 3;
76 	}
77 	if (statusCode == StatusCode::PIN_RETRY_COUNT_2)
78 	{
79 		return 2;
80 	}
81 	if (statusCode == StatusCode::PIN_SUSPENDED)
82 	{
83 		return 1;
84 	}
85 	if (statusCode == StatusCode::PIN_BLOCKED || statusCode == StatusCode::PIN_DEACTIVATED)
86 	{
87 		return 0;
88 	}
89 	return -1;
90 }
91 
92 
getSW1() const93 SW1 ResponseApdu::getSW1() const
94 {
95 	if (length() < RETURN_CODE_LENGTH)
96 	{
97 		qCCritical(card) << "Buffer too short, returning 0";
98 		return SW1::INVALID;
99 	}
100 	const char value = mBuffer.at(length() - RETURN_CODE_LENGTH);
101 	if (!Enum<SW1>::isValue(value))
102 	{
103 		qCCritical(card) << "Unknown SW1 value, returning INVALID, value:" << QString::number(value, 16);
104 		return SW1::INVALID;
105 	}
106 	return SW1(value);
107 }
108 
109 
getSW2() const110 char ResponseApdu::getSW2() const
111 {
112 	if (length() < 1)
113 	{
114 		qCCritical(card) << "Buffer too short, returning 0";
115 
116 		return 0;
117 	}
118 	return mBuffer.at(length() - 1);
119 }
120 
121 
getCardReturnCode() const122 CardReturnCode ResponseApdu::getCardReturnCode() const
123 {
124 	switch (getReturnCode())
125 	{
126 		case StatusCode::SUCCESS:
127 			return CardReturnCode::OK;
128 
129 		case StatusCode::INPUT_TIMEOUT:
130 			return CardReturnCode::INPUT_TIME_OUT;
131 
132 		case StatusCode::INPUT_CANCELLED:
133 			return CardReturnCode::CANCELLATION_BY_USER;
134 
135 		case StatusCode::PASSWORDS_DIFFER:
136 			return CardReturnCode::NEW_PIN_MISMATCH;
137 
138 		case StatusCode::PASSWORD_OUTOF_RANGE:
139 			return CardReturnCode::NEW_PIN_INVALID_LENGTH;
140 
141 		case StatusCode::PIN_BLOCKED:
142 			return CardReturnCode::PIN_BLOCKED;
143 
144 		default:
145 			return CardReturnCode::PROTOCOL_ERROR;
146 	}
147 
148 	Q_UNREACHABLE();
149 	return CardReturnCode::UNDEFINED;
150 }
151 
152 
153 #include "moc_ResponseApdu.cpp"
154